From 6ad2ca799345e1fb0259bdbf6e735af2ecee1732 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Tue, 8 Mar 2022 14:32:36 +0200 Subject: [PATCH 01/56] feat: initial sdk rewrite --- .gitignore | 3 +- .gitmodules | 3 + .husky/pre-commit | 6 + flagsmith-core.js | 2 +- .../environments/integrations/models.ts | 4 + flagsmith-engine/environments/models.ts | 50 + flagsmith-engine/environments/util.ts | 29 + flagsmith-engine/features/constants.ts | 4 + flagsmith-engine/features/models.ts | 105 + flagsmith-engine/features/util.ts | 38 + flagsmith-engine/identities/models.ts | 60 + flagsmith-engine/identities/traits/models.ts | 9 + flagsmith-engine/identities/util.ts | 30 + flagsmith-engine/index.ts | 92 + flagsmith-engine/organisations/models.ts | 25 + flagsmith-engine/organisations/util.ts | 11 + flagsmith-engine/projects/models.ts | 23 + flagsmith-engine/projects/util.ts | 18 + flagsmith-engine/segments/constants.ts | 31 + flagsmith-engine/segments/evaluators.ts | 72 + flagsmith-engine/segments/models.ts | 103 + flagsmith-engine/segments/util.ts | 29 + flagsmith-engine/utils/collections.ts | 14 + flagsmith-engine/utils/hashing/index.ts | 57 + flagsmith-engine/utils/index.ts | 10 + jest.config.js | 5 + package-lock.json | 7914 +++++++++- package.json | 19 +- .../engine-tests/engine-test-data/.gitignore | 1 + .../environment_n9fbf9h3v4fFgH3U3ngWhb.json | 12393 ++++++++++++++++ tests/engine-tests/engine-test-data/readme.md | 30 + tests/engine-tests/engine.test.ts | 52 + tests/index.js | 0 tests/unit/egine.test.ts | 96 + tests/unit/environments/builder.test.ts | 148 + tests/unit/environments/models.test.ts | 49 + tests/unit/features/models.test.ts | 72 + .../identities/identities_builders.test.ts | 85 + .../unit/identities/identities_models.test.ts | 105 + tests/unit/organization/models.test.ts | 12 + tests/unit/segments/segments_model.test.ts | 101 + tests/unit/segments/util.ts | 151 + tests/unit/utils.ts | 114 + tsconfig.json | 17 + 44 files changed, 22185 insertions(+), 7 deletions(-) create mode 100644 .gitmodules create mode 100644 .husky/pre-commit create mode 100644 flagsmith-engine/environments/integrations/models.ts create mode 100644 flagsmith-engine/environments/models.ts create mode 100644 flagsmith-engine/environments/util.ts create mode 100644 flagsmith-engine/features/constants.ts create mode 100644 flagsmith-engine/features/models.ts create mode 100644 flagsmith-engine/features/util.ts create mode 100644 flagsmith-engine/identities/models.ts create mode 100644 flagsmith-engine/identities/traits/models.ts create mode 100644 flagsmith-engine/identities/util.ts create mode 100644 flagsmith-engine/index.ts create mode 100644 flagsmith-engine/organisations/models.ts create mode 100644 flagsmith-engine/organisations/util.ts create mode 100644 flagsmith-engine/projects/models.ts create mode 100644 flagsmith-engine/projects/util.ts create mode 100644 flagsmith-engine/segments/constants.ts create mode 100644 flagsmith-engine/segments/evaluators.ts create mode 100644 flagsmith-engine/segments/models.ts create mode 100644 flagsmith-engine/segments/util.ts create mode 100644 flagsmith-engine/utils/collections.ts create mode 100644 flagsmith-engine/utils/hashing/index.ts create mode 100644 flagsmith-engine/utils/index.ts create mode 100644 jest.config.js create mode 100644 tests/engine-tests/engine-test-data/.gitignore create mode 100644 tests/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json create mode 100644 tests/engine-tests/engine-test-data/readme.md create mode 100644 tests/engine-tests/engine.test.ts create mode 100644 tests/index.js create mode 100644 tests/unit/egine.test.ts create mode 100644 tests/unit/environments/builder.test.ts create mode 100644 tests/unit/environments/models.test.ts create mode 100644 tests/unit/features/models.test.ts create mode 100644 tests/unit/identities/identities_builders.test.ts create mode 100644 tests/unit/identities/identities_models.test.ts create mode 100644 tests/unit/organization/models.test.ts create mode 100644 tests/unit/segments/segments_model.test.ts create mode 100644 tests/unit/segments/util.ts create mode 100644 tests/unit/utils.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index ae7418f..9b72b16 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ .idea/* -node_modules/ \ No newline at end of file +node_modules/ +build/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6ea4ff8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/engine-tests/engine-test-data"] + path = tests/engine-tests/engine-test-data + url = git@github.com:Flagsmith/engine-test-data.git diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..69d7abf --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,6 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npm run lint +git add ./flagsmith-engine ./tests +npm run test \ No newline at end of file diff --git a/flagsmith-core.js b/flagsmith-core.js index f851cb2..8456fd8 100644 --- a/flagsmith-core.js +++ b/flagsmith-core.js @@ -1,6 +1,6 @@ let fetch = require('node-fetch'); // https://github.com/node-fetch/node-fetch/issues/450 -if (typeof fetch.default !== "undefined") fetch = fetch.default +if (typeof fetch.default !== 'undefined') fetch = fetch.default; module.exports = class FlagsmithCore { normalizeFlags(flags) { diff --git a/flagsmith-engine/environments/integrations/models.ts b/flagsmith-engine/environments/integrations/models.ts new file mode 100644 index 0000000..ecce776 --- /dev/null +++ b/flagsmith-engine/environments/integrations/models.ts @@ -0,0 +1,4 @@ +export class IntegrationModel { + api_key?: string = undefined; + base_url?: string = undefined; +} diff --git a/flagsmith-engine/environments/models.ts b/flagsmith-engine/environments/models.ts new file mode 100644 index 0000000..92a0e62 --- /dev/null +++ b/flagsmith-engine/environments/models.ts @@ -0,0 +1,50 @@ +import { FeatureStateModel } from '../features/models'; +import { ProjectModel } from '../projects/models'; +import { IntegrationModel } from './integrations/models'; + +export class EnvironmentAPIKeyModel { + id: number; + key: string; + createdAt: number; + name: string; + clientApiKey: string; + expiresAt?: number; + active = true; + + constructor( + id: number, + key: string, + created_at: number, + name: string, + client_api_key: string, + expires_at?: number + ) { + this.id = id; + this.key = key; + this.createdAt = created_at; + this.name = name; + this.clientApiKey = client_api_key; + this.expiresAt = expires_at; + } + + isValid() { + return !!this.active && (!this.expiresAt || this.expiresAt > Date.now()); + } +} + +export class EnvironmentModel { + id: number; + apiKey: string; + project: ProjectModel; + featureStates: FeatureStateModel[] = []; + amplitude_config?: IntegrationModel; + segment_config?: IntegrationModel; + mixpanel_config?: IntegrationModel; + heap_config?: IntegrationModel; + + constructor(id: number, api_key: string, project: ProjectModel) { + this.id = id; + this.apiKey = api_key; + this.project = project; + } +} diff --git a/flagsmith-engine/environments/util.ts b/flagsmith-engine/environments/util.ts new file mode 100644 index 0000000..4a800c9 --- /dev/null +++ b/flagsmith-engine/environments/util.ts @@ -0,0 +1,29 @@ +import { buildFeatureStateModel } from '../features/util'; +import { buildProjectModel } from '../projects/util'; +import { EnvironmentAPIKeyModel, EnvironmentModel } from './models'; + +export function buildEnvironmentModel(environmentJSON: any) { + const project = buildProjectModel(environmentJSON.project); + const featureStates = environmentJSON.feature_states.map((fs: any) => + buildFeatureStateModel(fs) + ); + const environmentModel = new EnvironmentModel( + environmentJSON.id, + environmentJSON.api_key, + project + ); + environmentModel.featureStates = featureStates; + return environmentModel; +} + +export function buildEnvironmentAPIKeyModel(apiKeyJSON: any): EnvironmentAPIKeyModel { + const model = new EnvironmentAPIKeyModel( + apiKeyJSON.id, + apiKeyJSON.key, + Date.parse(apiKeyJSON.created_at), + apiKeyJSON.name, + apiKeyJSON.client_api_key + ); + + return model; +} diff --git a/flagsmith-engine/features/constants.ts b/flagsmith-engine/features/constants.ts new file mode 100644 index 0000000..cd37627 --- /dev/null +++ b/flagsmith-engine/features/constants.ts @@ -0,0 +1,4 @@ +export const CONSTANTS = { + STANDARD: 'STANDARD', + MULTIVARIATE: 'MULTIVARIATE' +}; diff --git a/flagsmith-engine/features/models.ts b/flagsmith-engine/features/models.ts new file mode 100644 index 0000000..3eb0a30 --- /dev/null +++ b/flagsmith-engine/features/models.ts @@ -0,0 +1,105 @@ +import { v4 as uuidv4 } from 'uuid'; +import { getHashedPercentateForObjIds } from '../utils/hashing'; + +export class FeatureModel { + id: number; + name: string; + type: string; + + constructor(id: number, name: string, type: string) { + this.id = id; + this.name = name; + this.type = type; + } + + eq(other: FeatureModel) { + return !!other && this.id === other.id; + } +} + +export class MultivariateFeatureOptionModel { + value: any; + id: number | undefined; + + constructor(value: any, id?: number) { + this.value = value; + this.id = id; + } +} + +export class MultivariateFeatureStateValueModel { + multivariateFeatureOption: MultivariateFeatureOptionModel; + percentageAllocation: number; + id: number; + mvFsValueUuid: string = uuidv4(); + + constructor( + multivariate_feature_option: MultivariateFeatureOptionModel, + percentage_allocation: number, + id: number, + mvFsValueUuid?: string + ) { + this.id = id; + this.percentageAllocation = percentage_allocation; + this.multivariateFeatureOption = multivariate_feature_option; + this.mvFsValueUuid = mvFsValueUuid || this.mvFsValueUuid; + } +} + +export class FeatureStateModel { + feature: FeatureModel; + enabled: boolean; + djangoID: number; + featurestateUUID: string = uuidv4(); + _value: any; + multivariateFeatureStateValues: MultivariateFeatureStateValueModel[] = []; + + constructor( + feature: FeatureModel, + enabled: boolean, + djangoID: number, + value?: any, + featurestate_uuid: string = uuidv4() + ) { + this.feature = feature; + this.enabled = enabled; + this.djangoID = djangoID; + this._value = value; + this.featurestateUUID = featurestate_uuid; + } + + setValue(value: any) { + this._value = value; + } + + getValue(identityId?: number | string) { + if (!!identityId && this.multivariateFeatureStateValues.length > 0) { + return this.getMultivariateValue(identityId); + } + return this._value; + } + + get_feature_state_value() { + return this.getValue(); + } + + getMultivariateValue(identityID: number | string) { + const percentageValue = getHashedPercentateForObjIds([ + this.djangoID || this.featurestateUUID, + identityID + ]); + + let startPercentage = 0; + const sortedF = this.multivariateFeatureStateValues.sort((a, b) => + !!(a.id && b.id) ? a.id - b.id : a.mvFsValueUuid > b.mvFsValueUuid ? -1 : 1 + ); + for (const myValue of sortedF) { + const limit = myValue.percentageAllocation + startPercentage; + if (startPercentage <= percentageValue && percentageValue < limit) { + return myValue.multivariateFeatureOption.value; + } + startPercentage = limit; + } + return this._value; + } +} diff --git a/flagsmith-engine/features/util.ts b/flagsmith-engine/features/util.ts new file mode 100644 index 0000000..fe9cfe9 --- /dev/null +++ b/flagsmith-engine/features/util.ts @@ -0,0 +1,38 @@ +import { + FeatureModel, + FeatureStateModel, + MultivariateFeatureOptionModel, + MultivariateFeatureStateValueModel +} from './models'; + +export function buildFeatureModel(featuresModelJSON: any): FeatureModel { + return new FeatureModel(featuresModelJSON.id, featuresModelJSON.name, featuresModelJSON.type); +} + +export function buildFeatureStateModel(featuresStateModelJSON: any): FeatureStateModel { + const featureStateModel = new FeatureStateModel( + buildFeatureModel(featuresStateModelJSON.feature), + featuresStateModelJSON.enabled, + featuresStateModelJSON.django_id, + featuresStateModelJSON.feature_state_value, + featuresStateModelJSON.uuid + ); + + const multivariateFeatureStateValues = featuresStateModelJSON.multivariate_feature_state_values + ? featuresStateModelJSON.multivariate_feature_state_values.map((fsv: any) => { + const featureOption = new MultivariateFeatureOptionModel( + fsv.multivariate_feature_option.value, + fsv.multivariate_feature_option.id + ); + return new MultivariateFeatureStateValueModel( + featureOption, + fsv.percentage_allocation, + fsv.id + ); + }) + : []; + + featureStateModel.multivariateFeatureStateValues = multivariateFeatureStateValues; + + return featureStateModel; +} diff --git a/flagsmith-engine/identities/models.ts b/flagsmith-engine/identities/models.ts new file mode 100644 index 0000000..db340ce --- /dev/null +++ b/flagsmith-engine/identities/models.ts @@ -0,0 +1,60 @@ +import { FeatureStateModel } from '../features/models'; +import { IdentityFeaturesList } from '../utils/collections'; +import { TraitModel } from './traits/models'; + +const { v4: uuidv4 } = require('uuid'); + +export class IdentityModel { + identifier: string; + environmentApiKey: string; + createdDate; + identityFeatures: IdentityFeaturesList; + identityTraits: TraitModel[]; + identityUuid: string; + djangoID: number | undefined; + + constructor( + created_date: string, + identity_traits: TraitModel[], + identity_features: IdentityFeaturesList, + environment_api_key: string, + identifier: string, + identity_uuid?: string + ) { + this.identityUuid = identity_uuid || uuidv4(); + this.createdDate = Date.parse(created_date) || Date.now(); + this.identityTraits = identity_traits; + this.identityFeatures = new IdentityFeaturesList(...identity_features); + this.environmentApiKey = environment_api_key; + this.identifier = identifier; + } + + get compositeKey() { + return IdentityModel.generateCompositeKey(this.environmentApiKey, this.identifier); + } + + static generateCompositeKey(env_key: string, identifier: string) { + return `${env_key}_${identifier}`; + } + + update_traits(traits: TraitModel[]) { + const existingTraits: Map = new Map(); + for (const trait of this.identityTraits) { + existingTraits.set(trait.traitKey, trait); + } + + for (const trait of traits) { + if (!!trait.traitValue) { + existingTraits.set(trait.traitKey, trait); + } else { + existingTraits.delete(trait.traitKey); + } + } + + this.identityTraits = []; + + for (const [k, v] of existingTraits.entries()) { + this.identityTraits.push(v); + } + } +} diff --git a/flagsmith-engine/identities/traits/models.ts b/flagsmith-engine/identities/traits/models.ts new file mode 100644 index 0000000..99f42f3 --- /dev/null +++ b/flagsmith-engine/identities/traits/models.ts @@ -0,0 +1,9 @@ +export class TraitModel { + traitKey: string; + traitValue: any; + + constructor(key: string, value: any) { + this.traitKey = key; + this.traitValue = value; + } +} diff --git a/flagsmith-engine/identities/util.ts b/flagsmith-engine/identities/util.ts new file mode 100644 index 0000000..6973ced --- /dev/null +++ b/flagsmith-engine/identities/util.ts @@ -0,0 +1,30 @@ +import { buildFeatureStateModel } from '../features/util'; +import { IdentityFeaturesList } from '../utils/collections'; +import { IdentityModel } from './models'; +import { TraitModel } from './traits/models'; + +export function buildTraitModel(traitJSON: any): TraitModel { + return new TraitModel(traitJSON.trait_key, traitJSON.trait_value); +} + +export function buildIdentityModel(identityJSON: any): IdentityModel { + const featureList = identityJSON.identity_features + ? new IdentityFeaturesList( + ...identityJSON.identity_features.map((f: any) => buildFeatureStateModel(f)) + ) + : []; + + const model = new IdentityModel( + identityJSON.created_date, + identityJSON.identity_traits + ? identityJSON.identity_traits.map((trait: any) => buildTraitModel(trait)) + : [], + featureList, + identityJSON.environment_api_key, + identityJSON.identifier, + identityJSON.identity_uuid + ); + + model.djangoID = identityJSON['django_id']; + return model; +} diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts new file mode 100644 index 0000000..92132fb --- /dev/null +++ b/flagsmith-engine/index.ts @@ -0,0 +1,92 @@ +import { EnvironmentModel } from './environments/models'; +import { FeatureStateModel } from './features/models'; +import { IdentityModel } from './identities/models'; +import { TraitModel } from './identities/traits/models'; +import { getIdentitySegments } from './segments/evaluators'; +import { SegmentModel } from './segments/models'; + +function getIdentityFeatureStatesDict( + environment: EnvironmentModel, + identity: IdentityModel, + override_traits?: TraitModel[] +) { + // Get feature states from the environment + const feature_states: { [key: number]: FeatureStateModel } = {}; + for (const fs of environment.featureStates) { + feature_states[fs.feature.id] = fs; + } + + // Override with any feature states defined by matching segments + const identity_segments: SegmentModel[] = getIdentitySegments( + environment, + identity, + override_traits + ); + for (const matching_segment of identity_segments) { + for (const feature_state of matching_segment.featureStates) { + // note that feature states are stored on the segment in descending priority + // order so we only care that the last one is added + // TODO: can we optimise this? + feature_states[feature_state.feature.id] = feature_state; + } + } + + // Override with any feature states defined directly the identity + for (const fs of identity.identityFeatures) { + if (feature_states[fs.feature.id]) { + feature_states[fs.feature.id] = fs; + } + } + return feature_states; +} + +export function getIdentityFeatureState( + environment: EnvironmentModel, + identity: IdentityModel, + feature_name: string, + override_traits?: TraitModel[] +): FeatureStateModel { + const featureStates = getIdentityFeatureStatesDict(environment, identity, override_traits); + + const matchingFeature = Object.values(featureStates).filter( + f => f.feature.name === feature_name + ); + + if (matchingFeature.length === 0) { + throw new Error('Feature State Not Found'); + } + + return matchingFeature[0]; +} + +export function getIdentityFeatureStates( + environment: EnvironmentModel, + identity: IdentityModel, + overrideTraits?: TraitModel[] +): FeatureStateModel[] { + const feature_states = Object.values( + getIdentityFeatureStatesDict(environment, identity, overrideTraits) + ); + + if (environment.project.hideDisabledFlags) { + return feature_states.filter(fs => !!fs.enabled); + } + return feature_states; +} + +export function getEnvironmentFeatureState(environment: EnvironmentModel, featureName: string) { + const featuresStates = environment.featureStates.filter(f => f.feature.name === featureName); + + if (featuresStates.length === 0) { + throw new Error('Feature State Not Found'); + } + + return featuresStates[0]; +} + +export function getEnvironmentFeatureStates(environment: EnvironmentModel): FeatureStateModel[] { + if (environment.project.hideDisabledFlags) { + return environment.featureStates.filter(fs => !!fs.enabled); + } + return environment.featureStates; +} diff --git a/flagsmith-engine/organisations/models.ts b/flagsmith-engine/organisations/models.ts new file mode 100644 index 0000000..8ee67f0 --- /dev/null +++ b/flagsmith-engine/organisations/models.ts @@ -0,0 +1,25 @@ +export class OrganisationModel { + id: number; + name: string; + featureAnalytics: boolean; + stopServingFlags: boolean; + persistTraitData: boolean; + + constructor( + id: number, + name: string, + feature_analytics: boolean, + stop_serving_flags: boolean, + persist_trait_data: boolean + ) { + this.id = id; + this.name = name; + this.featureAnalytics = feature_analytics; + this.stopServingFlags = stop_serving_flags; + this.persistTraitData = persist_trait_data; + } + + get unique_slug() { + return this.id.toString() + '-' + this.name; + } +} diff --git a/flagsmith-engine/organisations/util.ts b/flagsmith-engine/organisations/util.ts new file mode 100644 index 0000000..6e2df8f --- /dev/null +++ b/flagsmith-engine/organisations/util.ts @@ -0,0 +1,11 @@ +import { OrganisationModel } from './models'; + +export function buildOrganizationModel(organizationJSON: any): OrganisationModel { + return new OrganisationModel( + organizationJSON.id, + organizationJSON.name, + organizationJSON.feature_analytics, + organizationJSON.stop_serving_flags, + organizationJSON.persist_trait_data + ); +} diff --git a/flagsmith-engine/projects/models.ts b/flagsmith-engine/projects/models.ts new file mode 100644 index 0000000..a305c19 --- /dev/null +++ b/flagsmith-engine/projects/models.ts @@ -0,0 +1,23 @@ +import { OrganisationModel } from '../organisations/models'; +import { SegmentModel } from '../segments/models'; + +export class ProjectModel { + id: number; + name: string; + organisation: OrganisationModel; + hideDisabledFlags: boolean; + // FIXME + segments: SegmentModel[] = []; + + constructor( + id: number, + name: string, + hide_disabled_flags: boolean, + organization: OrganisationModel + ) { + this.id = id; + this.name = name; + this.hideDisabledFlags = hide_disabled_flags; + this.organisation = organization; + } +} diff --git a/flagsmith-engine/projects/util.ts b/flagsmith-engine/projects/util.ts new file mode 100644 index 0000000..e88037c --- /dev/null +++ b/flagsmith-engine/projects/util.ts @@ -0,0 +1,18 @@ +import { buildOrganizationModel } from '../organisations/util'; +import { SegmentModel } from '../segments/models'; +import { buildSegmentModel } from '../segments/util'; +import { ProjectModel } from './models'; + +export function buildProjectModel(projectJSON: any): ProjectModel { + const segments: SegmentModel[] = projectJSON['segments'] + ? projectJSON['segments'].map((s: any) => buildSegmentModel(s)) + : []; + const model = new ProjectModel( + projectJSON.id, + projectJSON.name, + projectJSON.hide_disabled_flags, + buildOrganizationModel(projectJSON.organisation) + ); + model.segments = segments; + return model; +} diff --git a/flagsmith-engine/segments/constants.ts b/flagsmith-engine/segments/constants.ts new file mode 100644 index 0000000..ba6fafc --- /dev/null +++ b/flagsmith-engine/segments/constants.ts @@ -0,0 +1,31 @@ +// Segment Rules +export const ALL_RULE = 'ALL'; +export const ANY_RULE = 'ANY'; +export const NONE_RULE = 'NONE'; + +export const RULE_TYPES = [ALL_RULE, ANY_RULE, NONE_RULE]; + +// Segment Condition Operators +export const EQUAL = 'EQUAL'; +export const GREATER_THAN = 'GREATER_THAN'; +export const LESS_THAN = 'LESS_THAN'; +export const LESS_THAN_INCLUSIVE = 'LESS_THAN_INCLUSIVE'; +export const CONTAINS = 'CONTAINS'; +export const GREATER_THAN_INCLUSIVE = 'GREATER_THAN_INCLUSIVE'; +export const NOT_CONTAINS = 'NOT_CONTAINS'; +export const NOT_EQUAL = 'NOT_EQUAL'; +export const REGEX = 'REGEX'; +export const PERCENTAGE_SPLIT = 'PERCENTAGE_SPLIT'; + +export const CONDITION_OPERATORS = { + EQUAL, + GREATER_THAN, + LESS_THAN, + LESS_THAN_INCLUSIVE, + CONTAINS, + GREATER_THAN_INCLUSIVE, + NOT_CONTAINS, + NOT_EQUAL, + REGEX, + PERCENTAGE_SPLIT +}; diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts new file mode 100644 index 0000000..54bd7d3 --- /dev/null +++ b/flagsmith-engine/segments/evaluators.ts @@ -0,0 +1,72 @@ +import { EnvironmentModel } from '../environments/models'; +import { IdentityModel } from '../identities/models'; +import { TraitModel } from '../identities/traits/models'; +import { getHashedPercentateForObjIds } from '../utils/hashing'; +import { PERCENTAGE_SPLIT } from './constants'; +import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models'; + +export function getIdentitySegments( + environment: EnvironmentModel, + identity: IdentityModel, + overrideTraits?: TraitModel[] +): SegmentModel[] { + return environment.project.segments.filter(segment => + evaluateIdentityInSegment(identity, segment, overrideTraits) + ); +} + +export function evaluateIdentityInSegment( + identity: IdentityModel, + segment: SegmentModel, + overrideTraits?: TraitModel[] +): boolean { + return ( + segment.rules.length > 0 && + segment.rules.filter(rule => + traitsMatchSegmentRule( + overrideTraits || identity.identityTraits, + rule, + segment.id, + identity.compositeKey + ) + ).length === segment.rules.length + ); +} + +function traitsMatchSegmentRule( + identityTraits: TraitModel[], + rule: SegmentRuleModel, + segmentId: number | string, + identityId: number | string +): boolean { + const matchesConditions = + rule.conditions.length > 0 + ? rule.matchingFunction()( + rule.conditions.map(condition => + traitsMatchSegmentCondition(identityTraits, condition, segmentId, identityId) + ) + ) + : true; + return ( + matchesConditions && + rule.rules.filter(rule => + traitsMatchSegmentRule(identityTraits, rule, segmentId, identityId) + ).length === rule.rules.length + ); +} + +function traitsMatchSegmentCondition( + identity_traits: TraitModel[], + condition: SegmentConditionModel, + segmentId: number | string, + identityId: number | string +): boolean { + if (condition.operator == PERCENTAGE_SPLIT) { + return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); + } + + const traits = identity_traits.filter(t => t.traitKey === condition.property_); + const trait = traits.length > 0 ? traits[0] : undefined; + + return trait ? condition.matchesTraitValue(trait.traitValue) : false; +} diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts new file mode 100644 index 0000000..40ee5a4 --- /dev/null +++ b/flagsmith-engine/segments/models.ts @@ -0,0 +1,103 @@ +import { FeatureStateModel } from '../features/models'; +import { getCastingFunction as getCastingFunction } from '../utils'; +import { + ALL_RULE, + ANY_RULE, + NONE_RULE, + NOT_CONTAINS, + REGEX, + CONDITION_OPERATORS +} from './constants'; + +export const all = (iterable: Array) => iterable.filter(e => !!e).length === iterable.length; +export const any = (iterable: Array) => iterable.filter(e => !!e).length > 0; + +export const matchingFunctions = { + [CONDITION_OPERATORS.EQUAL]: (thisValue: any, otherValue: any) => thisValue == otherValue, + [CONDITION_OPERATORS.GREATER_THAN]: (thisValue: any, otherValue: any) => otherValue > thisValue, + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE]: (thisValue: any, otherValue: any) => + otherValue >= thisValue, + [CONDITION_OPERATORS.LESS_THAN]: (thisValue: any, otherValue: any) => thisValue > otherValue, + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE]: (thisValue: any, otherValue: any) => + thisValue >= otherValue, + [CONDITION_OPERATORS.NOT_EQUAL]: (thisValue: any, otherValue: any) => thisValue != otherValue, + [CONDITION_OPERATORS.CONTAINS]: (thisValue: any, otherValue: any) => + otherValue.includes(thisValue), + [CONDITION_OPERATORS.NOT_CONTAINS]: (thisValue: any, otherValue: any) => + !otherValue.includes(thisValue) +}; + +export class SegmentConditionModel { + EXCEPTION_OPERATOR_METHODS: { [key: string]: string } = { + [NOT_CONTAINS]: 'evaluateNotContains', + [REGEX]: 'evaluateRegex' + }; + + operator: string; + value: string; + property_: string | undefined; + + constructor(operator: string, value: string, property?: string) { + this.operator = operator; + this.value = value; + this.property_ = property; + } + + matchesTraitValue(traitValue: any) { + const evaluators: { [key: string]: CallableFunction } = { + evaluateNotContains: (traitValue: any) => { + return !traitValue.includes(this.value); + }, + evaluateRegex: (traitValue: any) => { + return !!traitValue.match(new RegExp(this.value)); + } + }; + + // TODO: move this logic to the evaluator module + if (this.EXCEPTION_OPERATOR_METHODS[this.operator]) { + const evaluatorFunction = evaluators[this.EXCEPTION_OPERATOR_METHODS[this.operator]]; + return evaluatorFunction(traitValue); + } + + const defaultFunction = (x: any, y: any) => false; + + const matchingFunction = matchingFunctions[this.operator] || defaultFunction; + + const castToTypeOfTraitValue = getCastingFunction(traitValue); + return matchingFunction(castToTypeOfTraitValue(this.value), traitValue); + } +} + +export class SegmentRuleModel { + type: string; + rules: SegmentRuleModel[] = []; + conditions: SegmentConditionModel[] = []; + + constructor(type: string) { + this.type = type; + } + + static none(iterable: Array) { + return iterable.filter(e => !!e).length === 0; + } + + matchingFunction(): CallableFunction { + return { + [ANY_RULE]: any, + [ALL_RULE]: all, + [NONE_RULE]: SegmentRuleModel.none + }[this.type] as CallableFunction; + } +} + +export class SegmentModel { + id: number; + name: string; + rules: SegmentRuleModel[] = []; + featureStates: FeatureStateModel[] = []; + + constructor(id: number, name: string) { + this.id = id; + this.name = name; + } +} diff --git a/flagsmith-engine/segments/util.ts b/flagsmith-engine/segments/util.ts new file mode 100644 index 0000000..aa939bf --- /dev/null +++ b/flagsmith-engine/segments/util.ts @@ -0,0 +1,29 @@ +import { buildFeatureStateModel } from '../features/util'; +import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models'; + +export function buildSegmentConditionModel(segmentConditionJSON: any): SegmentConditionModel { + return new SegmentConditionModel( + segmentConditionJSON.operator, + segmentConditionJSON.value, + segmentConditionJSON.property_ + ); +} + +export function buildSegmentRuleModel(ruleModelJSON: any): SegmentRuleModel { + const ruleModel = new SegmentRuleModel(ruleModelJSON.type); + + ruleModel.rules = ruleModelJSON.rules.map((r: any) => buildSegmentRuleModel(r)); + ruleModel.conditions = ruleModelJSON.conditions.map((c: any) => buildSegmentConditionModel(c)); + return ruleModel; +} + +export function buildSegmentModel(segmentModelJSON: any): SegmentModel { + const model = new SegmentModel(segmentModelJSON.id, segmentModelJSON.name); + + model.featureStates = segmentModelJSON['feature_states'].map((fs: any) => + buildFeatureStateModel(fs) + ); + model.rules = segmentModelJSON['rules'].map((r: any) => buildSegmentRuleModel(r)); + + return model; +} diff --git a/flagsmith-engine/utils/collections.ts b/flagsmith-engine/utils/collections.ts new file mode 100644 index 0000000..451ec14 --- /dev/null +++ b/flagsmith-engine/utils/collections.ts @@ -0,0 +1,14 @@ +import { FeatureStateModel } from '../features/models'; + +export class IdentityFeaturesList extends Array { + public push(...e: FeatureStateModel[]): number { + for (const [_, item] of e.entries()) { + for (const [k, v] of this.entries()) { + if (v.djangoID === item.djangoID) { + throw new Error('feature state for this feature already exists'); + } + } + } + return super.push(...e); + } +} diff --git a/flagsmith-engine/utils/hashing/index.ts b/flagsmith-engine/utils/hashing/index.ts new file mode 100644 index 0000000..c2da503 --- /dev/null +++ b/flagsmith-engine/utils/hashing/index.ts @@ -0,0 +1,57 @@ +import md5 from 'md5'; +import bigInt from 'big-integer'; + +// def get_hashed_percentage_for_object_ids( +// object_ids: typing.Iterable[typing.Any], iterations: int = 1 +// ) -> float: +// """ +// Given a list of object ids, get a floating point number between 0 and 1 based on +// the hash of those ids. This should give the same value every time for any +// list of ids. + +// :param object_ids: list of object ids to calculate the has for +// :param iterations: num times to include each id in the generated string to hash +// :return: (float) number between 0 (inclusive) and 100 (exclusive) +// """ + +const makeRepeated = (arr: Array, repeats: number) => + Array.from({ length: repeats }, () => arr).flat(); + +function h2d(s: any): string { + function add(x: any, y: any) { + var c = 0, + r = []; + var x = x.split('').map(Number); + var y = y.split('').map(Number); + while (x.length || y.length) { + var s = (x.pop() || 0) + (y.pop() || 0) + c; + r.unshift(s < 10 ? s : s - 10); + c = s < 10 ? 0 : 1; + } + if (c) r.unshift(c); + return r.join(''); + } + + var dec = '0'; + s.split('').forEach(function (chr: any) { + var n = parseInt(chr, 16); + for (var t = 8; t; t >>= 1) { + dec = add(dec, dec); + if (n & t) dec = add(dec, '1'); + } + }); + return dec; +} + +export function getHashedPercentateForObjIds(objectIds: Array, iterations = 1): number { + let to_hash = makeRepeated(objectIds, iterations).join(','); + const hashedValue = md5(to_hash); + const hashedInt = bigInt(h2d(hashedValue)); + const value = (hashedInt.mod(9999).toJSNumber() / 9998) * 100; + + if (value === 100) { + return getHashedPercentateForObjIds(objectIds, iterations + 1); + } + + return value; +} diff --git a/flagsmith-engine/utils/index.ts b/flagsmith-engine/utils/index.ts new file mode 100644 index 0000000..9470ac0 --- /dev/null +++ b/flagsmith-engine/utils/index.ts @@ -0,0 +1,10 @@ +export function getCastingFunction(input: any): CallableFunction { + switch (typeof input) { + case 'boolean': + return (x: any) => !['False', 'false'].includes(x); + case 'number': + return (x: any) => parseFloat(x); + default: + return (x: any) => String(x); + } +} diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..519affd --- /dev/null +++ b/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node' +}; diff --git a/package-lock.json b/package-lock.json index 97819ba..3c7dbd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,7929 @@ { "name": "flagsmith-nodejs", - "version": "1.0.9", - "lockfileVersion": 1, + "version": "1.1.1", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "flagsmith-nodejs", + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "big-integer": "^1.6.51", + "md5": "^2.3.0", + "node-fetch": "^2.1.2", + "uuid": "^8.3.2" + }, + "devDependencies": { + "@types/jest": "^27.4.1", + "@types/md5": "^2.3.2", + "@types/uuid": "^8.3.4", + "esbuild": "^0.14.25", + "husky": "^7.0.4", + "jest": "^27.5.1", + "prettier": "^2.2.1", + "ts-jest": "^27.1.3", + "typescript": "^4.6.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", + "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.4.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", + "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", + "dev": true, + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/md5": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.2.tgz", + "integrity": "sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", + "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001312", + "electron-to-chromium": "^1.4.71", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "engines": { + "node": "*" + } + }, + "node_modules/ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "engines": { + "node": "*" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.75", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz", + "integrity": "sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", + "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.25", + "esbuild-android-arm64": "0.14.25", + "esbuild-darwin-64": "0.14.25", + "esbuild-darwin-arm64": "0.14.25", + "esbuild-freebsd-64": "0.14.25", + "esbuild-freebsd-arm64": "0.14.25", + "esbuild-linux-32": "0.14.25", + "esbuild-linux-64": "0.14.25", + "esbuild-linux-arm": "0.14.25", + "esbuild-linux-arm64": "0.14.25", + "esbuild-linux-mips64le": "0.14.25", + "esbuild-linux-ppc64le": "0.14.25", + "esbuild-linux-riscv64": "0.14.25", + "esbuild-linux-s390x": "0.14.25", + "esbuild-netbsd-64": "0.14.25", + "esbuild-openbsd-64": "0.14.25", + "esbuild-sunos-64": "0.14.25", + "esbuild-windows-32": "0.14.25", + "esbuild-windows-64": "0.14.25", + "esbuild-windows-arm64": "0.14.25" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz", + "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz", + "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz", + "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz", + "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz", + "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz", + "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz", + "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz", + "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz", + "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz", + "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz", + "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz", + "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz", + "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz", + "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz", + "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz", + "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz", + "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz", + "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz", + "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz", + "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-jest": { + "version": "27.1.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", + "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "esbuild": "~0.14.0", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + } + }, "dependencies": { + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true + }, + "@babel/core": { + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", + "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" + } + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + } + }, + "@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + } + }, + "@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + } + }, + "@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + } + }, + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "27.4.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", + "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", + "dev": true, + "requires": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "@types/md5": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.2.tgz", + "integrity": "sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og==", + "dev": true + }, + "@types/node": { + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "dev": true + }, + "@types/prettier": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "requires": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browserslist": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", + "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001312", + "electron-to-chromium": "^1.4.71", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.4.75", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz", + "integrity": "sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q==", + "dev": true + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "esbuild": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", + "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.25", + "esbuild-android-arm64": "0.14.25", + "esbuild-darwin-64": "0.14.25", + "esbuild-darwin-arm64": "0.14.25", + "esbuild-freebsd-64": "0.14.25", + "esbuild-freebsd-arm64": "0.14.25", + "esbuild-linux-32": "0.14.25", + "esbuild-linux-64": "0.14.25", + "esbuild-linux-arm": "0.14.25", + "esbuild-linux-arm64": "0.14.25", + "esbuild-linux-mips64le": "0.14.25", + "esbuild-linux-ppc64le": "0.14.25", + "esbuild-linux-riscv64": "0.14.25", + "esbuild-linux-s390x": "0.14.25", + "esbuild-netbsd-64": "0.14.25", + "esbuild-openbsd-64": "0.14.25", + "esbuild-sunos-64": "0.14.25", + "esbuild-windows-32": "0.14.25", + "esbuild-windows-64": "0.14.25", + "esbuild-windows-arm64": "0.14.25" + } + }, + "esbuild-android-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz", + "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz", + "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz", + "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz", + "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz", + "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz", + "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz", + "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz", + "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz", + "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz", + "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz", + "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz", + "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz", + "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz", + "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz", + "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz", + "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz", + "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz", + "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz", + "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.25", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz", + "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dev": true, + "requires": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + } + }, + "jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "requires": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + }, + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "requires": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + } + }, + "jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "requires": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + } + }, + "jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "requires": { + "mime-db": "1.51.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "node-fetch": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prettier": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "ts-jest": { + "version": "27.1.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", + "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true, + "requires": {} + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } } diff --git a/package.json b/package.json index 7fba721..bf0aa4e 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,25 @@ ], "license": "MIT", "scripts": { - "lint": "prettier --write ." + "lint": "prettier --write .", + "test": "jest --coverage --coverageReporters='text'", + "prepare": "husky install" }, "dependencies": { - "node-fetch": "^2.1.2" + "big-integer": "^1.6.51", + "md5": "^2.3.0", + "node-fetch": "^2.1.2", + "uuid": "^8.3.2" }, "devDependencies": { - "prettier": "^2.2.1" + "@types/jest": "^27.4.1", + "@types/md5": "^2.3.2", + "@types/uuid": "^8.3.4", + "esbuild": "^0.14.25", + "husky": "^7.0.4", + "jest": "^27.5.1", + "prettier": "^2.2.1", + "ts-jest": "^27.1.3", + "typescript": "^4.6.2" } } diff --git a/tests/engine-tests/engine-test-data/.gitignore b/tests/engine-tests/engine-test-data/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/tests/engine-tests/engine-test-data/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/tests/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json b/tests/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json new file mode 100644 index 0000000..de53092 --- /dev/null +++ b/tests/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json @@ -0,0 +1,12393 @@ +{ + "environment": { + "project": { + "hide_disabled_flags": false, + "segments": [ + { + "name": "regular_segment", + "feature_states": [ + { + "feature_state_value": "segment_override", + "multivariate_feature_state_values": [], + "django_id": 81027, + "feature": { + "id": 15058, + "type": "STANDARD", + "name": "string_feature" + }, + "enabled": false + } + ], + "id": 4267, + "rules": [ + { + "type": "ALL", + "conditions": [], + "rules": [ + { + "type": "ANY", + "conditions": [ + { + "value": "40", + "property_": "age", + "operator": "LESS_THAN" + } + ], + "rules": [] + }, + { + "type": "ANY", + "conditions": [ + { + "value": "21", + "property_": "age", + "operator": "GREATER_THAN_INCLUSIVE" + } + ], + "rules": [] + }, + { + "type": "ANY", + "conditions": [ + { + "value": "green", + "property_": "favourite_colour", + "operator": "EQUAL" + }, + { + "value": "blue", + "property_": "favourite_colour", + "operator": "EQUAL" + } + ], + "rules": [] + } + ] + } + ] + }, + { + "name": "10_percent", + "feature_states": [ + { + "feature_state_value": "", + "multivariate_feature_state_values": [], + "django_id": 81026, + "feature": { + "id": 15060, + "type": "STANDARD", + "name": "basic_flag" + }, + "enabled": true + } + ], + "id": 4268, + "rules": [ + { + "type": "ALL", + "conditions": [], + "rules": [ + { + "type": "ANY", + "conditions": [ + { + "value": "0.1", + "property_": "", + "operator": "PERCENTAGE_SPLIT" + } + ], + "rules": [] + } + ] + } + ] + } + ], + "name": "Edge API Test Project", + "id": 5359, + "organisation": { + "persist_trait_data": true, + "name": "Flagsmith", + "feature_analytics": false, + "stop_serving_flags": false, + "id": 13 + } + }, + "api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "feature_states": [ + { + "feature_state_value": "foo", + "multivariate_feature_state_values": [], + "django_id": 78978, + "feature": { + "id": 15058, + "type": "STANDARD", + "name": "string_feature" + }, + "enabled": true + }, + { + "feature_state_value": 1234, + "multivariate_feature_state_values": [], + "django_id": 78980, + "feature": { + "id": 15059, + "type": "STANDARD", + "name": "integer_feature" + }, + "enabled": true + }, + { + "feature_state_value": null, + "multivariate_feature_state_values": [], + "django_id": 78982, + "feature": { + "id": 15060, + "type": "STANDARD", + "name": "basic_flag" + }, + "enabled": false + }, + { + "feature_state_value": "12.34", + "multivariate_feature_state_values": [], + "django_id": 78984, + "feature": { + "id": 15061, + "type": "STANDARD", + "name": "float_feature" + }, + "enabled": true + }, + { + "feature_state_value": "foo", + "multivariate_feature_state_values": [ + { + "id": 3404, + "multivariate_feature_option": { + "value": "baz" + }, + "percentage_allocation": 30.0 + }, + { + "id": 3402, + "multivariate_feature_option": { + "value": "bar" + }, + "percentage_allocation": 30.0 + } + ], + "django_id": 78986, + "feature": { + "id": 15062, + "type": "MULTIVARIATE", + "name": "mv_feature" + }, + "enabled": true + } + ], + "id": 12561 + }, + "identities_and_responses": [ + { + "identity": { + "identity_uuid": "10f435fb-66fa-4e5e-9787-75729a4e8372", + "identifier": "54463d93-392f-493a-90b5-a1d3afe60f4b", + "created_date": "2021-12-15T14:40:00.880997", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_54463d93-392f-493a-90b5-a1d3afe60f4b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 49 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32102998 + }, + "response": { + "traits": [ + { + "id": 26678015, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678016, + "trait_key": "age", + "trait_value": 49 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "275b5d01-6ffb-4183-9c4e-b031a4b4af56", + "identifier": "7765d342-16c5-4c1c-a461-459d39f65b85", + "created_date": "2021-12-15T14:40:00.881011", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7765d342-16c5-4c1c-a461-459d39f65b85", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 93 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103670 + }, + "response": { + "traits": [ + { + "id": 26678279, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678280, + "trait_key": "age", + "trait_value": 93 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "baebd517-e00e-4d53-843d-8e3db194c6aa", + "identifier": "ce99d7bb-2fbd-4fb3-8c4d-0f4a11c5a9aa", + "created_date": "2021-12-15T14:40:00.881018", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_ce99d7bb-2fbd-4fb3-8c4d-0f4a11c5a9aa", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 56 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103671 + }, + "response": { + "traits": [ + { + "id": 26678281, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678282, + "trait_key": "age", + "trait_value": 56 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "6e707eed-851d-487c-996b-4fc207c8b95d", + "identifier": "7fb675cf-91fc-439e-8e5f-896bbaa46319", + "created_date": "2021-12-15T14:40:00.881024", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7fb675cf-91fc-439e-8e5f-896bbaa46319", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 71 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103674 + }, + "response": { + "traits": [ + { + "id": 26678283, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678284, + "trait_key": "age", + "trait_value": 71 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "8e3fe9c7-5ec7-4547-a4d1-6b90a0b25cd4", + "identifier": "f0ca10b8-7088-4336-ae8c-5332e91f1554", + "created_date": "2021-12-15T14:40:00.881031", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_f0ca10b8-7088-4336-ae8c-5332e91f1554", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 88 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103676 + }, + "response": { + "traits": [ + { + "id": 26678285, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678286, + "trait_key": "age", + "trait_value": 88 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "dfb7b7ec-510c-4367-8a00-a5692cb53fb9", + "identifier": "ef981b6d-22d8-4daa-ab2d-f3f26db80a86", + "created_date": "2021-12-15T14:40:00.881037", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_ef981b6d-22d8-4daa-ab2d-f3f26db80a86", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 84 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103677 + }, + "response": { + "traits": [ + { + "id": 26678287, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678288, + "trait_key": "age", + "trait_value": 84 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "639b6c09-c52d-4b57-ab5a-aac5d0b5a3f7", + "identifier": "a2f85378-ea82-44c0-8998-be477402379c", + "created_date": "2021-12-15T14:40:00.881045", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_a2f85378-ea82-44c0-8998-be477402379c", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 78 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103679 + }, + "response": { + "traits": [ + { + "id": 26678290, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678291, + "trait_key": "age", + "trait_value": 78 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "a1862f60-16f4-4658-b495-f05c6ff3c6f5", + "identifier": "64ebc978-1f6a-4c22-8f5b-8b0f83478ef1", + "created_date": "2021-12-15T14:40:00.881051", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_64ebc978-1f6a-4c22-8f5b-8b0f83478ef1", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 85 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103681 + }, + "response": { + "traits": [ + { + "id": 26678292, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678293, + "trait_key": "age", + "trait_value": 85 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "0133a745-c508-436c-b142-6fb214e6984a", + "identifier": "2db1db6a-2dab-4416-8510-b2a99db4f05a", + "created_date": "2021-12-15T14:40:00.881058", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2db1db6a-2dab-4416-8510-b2a99db4f05a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 60 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103682 + }, + "response": { + "traits": [ + { + "id": 26678294, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678295, + "trait_key": "age", + "trait_value": 60 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "fd9ebd93-4acb-4402-b923-92f74dda62fa", + "identifier": "9f7d2eb7-e01c-4bec-9738-5eaeaa6bf776", + "created_date": "2021-12-15T14:40:00.881064", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_9f7d2eb7-e01c-4bec-9738-5eaeaa6bf776", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 51 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103683 + }, + "response": { + "traits": [ + { + "id": 26678296, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678297, + "trait_key": "age", + "trait_value": 51 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "8e619996-500f-430e-b234-3cf8c7f83161", + "identifier": "e5af06dd-d3a1-4f53-9185-8989b6eaa848", + "created_date": "2021-12-15T14:40:00.881070", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_e5af06dd-d3a1-4f53-9185-8989b6eaa848", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 6 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103684 + }, + "response": { + "traits": [ + { + "id": 26678298, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678299, + "trait_key": "age", + "trait_value": 6 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "f22be96e-d364-4017-8929-7771446a861e", + "identifier": "81b634c1-fde0-4d32-af2b-2ddd08d5dee6", + "created_date": "2021-12-15T14:40:00.881076", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_81b634c1-fde0-4d32-af2b-2ddd08d5dee6", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 66 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103685 + }, + "response": { + "traits": [ + { + "id": 26678300, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678301, + "trait_key": "age", + "trait_value": 66 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "601bb6b9-8e55-4b3c-8709-9f047dc30711", + "identifier": "dbcc4f61-44c2-4117-a5fd-16237b66f46d", + "created_date": "2021-12-15T14:40:00.881082", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_dbcc4f61-44c2-4117-a5fd-16237b66f46d", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 35 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103686 + }, + "response": { + "traits": [ + { + "id": 26678302, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678303, + "trait_key": "age", + "trait_value": 35 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "fa5753f0-3e0e-4b4b-9386-a8ed5fb60322", + "identifier": "388b793f-5843-46c9-af6b-a942b52527b2", + "created_date": "2021-12-15T14:40:00.881088", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_388b793f-5843-46c9-af6b-a942b52527b2", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 30 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103688 + }, + "response": { + "traits": [ + { + "id": 26678304, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678305, + "trait_key": "age", + "trait_value": 30 + } + ], + "flags": [ + { + "id": 81027, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "segment_override", + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": 9893 + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "bd2749dd-4026-4d79-83c3-3882df2643f8", + "identifier": "3719f827-9c23-4956-b82a-7c2f5102479f", + "created_date": "2021-12-15T14:40:00.881095", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3719f827-9c23-4956-b82a-7c2f5102479f", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 77 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103689 + }, + "response": { + "traits": [ + { + "id": 26678306, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678307, + "trait_key": "age", + "trait_value": 77 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "448ee1bf-6417-4688-a2a2-d2172773a94a", + "identifier": "db0436cb-ede2-42e4-b2d5-65af13e0852a", + "created_date": "2021-12-15T14:40:00.881100", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_db0436cb-ede2-42e4-b2d5-65af13e0852a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 48 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103690 + }, + "response": { + "traits": [ + { + "id": 26678308, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678309, + "trait_key": "age", + "trait_value": 48 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "8b4a3afc-4d75-456c-b6d2-542170cd068b", + "identifier": "397cd01d-c6a1-451c-8795-4c9686c22a3b", + "created_date": "2021-12-15T14:40:00.881106", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_397cd01d-c6a1-451c-8795-4c9686c22a3b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 86 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103692 + }, + "response": { + "traits": [ + { + "id": 26678310, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678311, + "trait_key": "age", + "trait_value": 86 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "871d212c-6b59-4c23-b3e3-e7a695ebc3c9", + "identifier": "32fd6b46-69d0-4123-8e35-ca4401e8bc3e", + "created_date": "2021-12-15T14:40:00.881112", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_32fd6b46-69d0-4123-8e35-ca4401e8bc3e", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 63 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103693 + }, + "response": { + "traits": [ + { + "id": 26678312, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678313, + "trait_key": "age", + "trait_value": 63 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "b428ae53-8688-452e-ad9d-450ed99aa4b1", + "identifier": "31f5d2d7-3736-478c-a887-e77c16cc8dfd", + "created_date": "2021-12-15T14:40:00.881118", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_31f5d2d7-3736-478c-a887-e77c16cc8dfd", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 37 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103695 + }, + "response": { + "traits": [ + { + "id": 26678314, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678315, + "trait_key": "age", + "trait_value": 37 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "82fd8c76-9943-454d-9c35-1f68af410aea", + "identifier": "15ef44aa-34b5-4366-a201-c80e33d9f169", + "created_date": "2021-12-15T14:40:00.881124", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_15ef44aa-34b5-4366-a201-c80e33d9f169", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 32 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103696 + }, + "response": { + "traits": [ + { + "id": 26678316, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678317, + "trait_key": "age", + "trait_value": 32 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "6e04dd89-0028-4f2c-b87f-17e71e414085", + "identifier": "2d6d8b94-504c-437e-afd2-c84cc4e72b8b", + "created_date": "2021-12-15T14:40:00.881130", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2d6d8b94-504c-437e-afd2-c84cc4e72b8b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 83 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103699 + }, + "response": { + "traits": [ + { + "id": 26678318, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678319, + "trait_key": "age", + "trait_value": 83 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c49440f9-1b03-464b-8d98-4cdd7bd8480d", + "identifier": "20e6204b-e396-4d4b-a861-bb136c276ac2", + "created_date": "2021-12-15T14:40:00.881135", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_20e6204b-e396-4d4b-a861-bb136c276ac2", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 68 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103700 + }, + "response": { + "traits": [ + { + "id": 26678320, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678321, + "trait_key": "age", + "trait_value": 68 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "575cac45-a94d-4b91-ae86-10f692c30aa2", + "identifier": "c8159d13-3b99-4355-84df-c8e541d55384", + "created_date": "2021-12-15T14:40:00.881142", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c8159d13-3b99-4355-84df-c8e541d55384", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 76 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103702 + }, + "response": { + "traits": [ + { + "id": 26678322, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678323, + "trait_key": "age", + "trait_value": 76 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "fd29ee25-7b53-4947-8910-a7e261ae9ef7", + "identifier": "42c798b6-1a36-4cf3-8df0-b6347020323a", + "created_date": "2021-12-15T14:40:00.881148", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_42c798b6-1a36-4cf3-8df0-b6347020323a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 62 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103703 + }, + "response": { + "traits": [ + { + "id": 26678324, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678325, + "trait_key": "age", + "trait_value": 62 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "491088a0-337c-4ebb-a6f0-d116ebaf5d0f", + "identifier": "170effbe-4388-49a5-9872-700688b628b9", + "created_date": "2021-12-15T14:40:00.881153", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_170effbe-4388-49a5-9872-700688b628b9", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 69 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103704 + }, + "response": { + "traits": [ + { + "id": 26678326, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678327, + "trait_key": "age", + "trait_value": 69 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "aa5a77b1-241d-4af4-a580-370d85965f03", + "identifier": "042b3a46-4575-419a-8a2f-62baa3226668", + "created_date": "2021-12-15T14:40:00.881161", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_042b3a46-4575-419a-8a2f-62baa3226668", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 20 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103705 + }, + "response": { + "traits": [ + { + "id": 26678328, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678329, + "trait_key": "age", + "trait_value": 20 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "40cdc7cd-765b-4f71-8b1e-7fa723116201", + "identifier": "83295382-6d39-4db1-ac66-1ebb6e98b70e", + "created_date": "2021-12-15T14:40:00.881167", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_83295382-6d39-4db1-ac66-1ebb6e98b70e", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 91 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103706 + }, + "response": { + "traits": [ + { + "id": 26678330, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678331, + "trait_key": "age", + "trait_value": 91 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c136ba1f-1bdb-43d3-af72-c1a7e33677de", + "identifier": "3debf4d7-3aff-4a8e-98fe-35d3add7f9fb", + "created_date": "2021-12-15T14:40:00.881173", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3debf4d7-3aff-4a8e-98fe-35d3add7f9fb", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 92 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103707 + }, + "response": { + "traits": [ + { + "id": 26678332, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678333, + "trait_key": "age", + "trait_value": 92 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "b349658d-8aac-4fc7-bd64-c48a4d143c14", + "identifier": "fc300e2a-b1b8-4408-8830-676e47abaf2c", + "created_date": "2021-12-15T14:40:00.881178", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_fc300e2a-b1b8-4408-8830-676e47abaf2c", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 34 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103708 + }, + "response": { + "traits": [ + { + "id": 26678334, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678335, + "trait_key": "age", + "trait_value": 34 + } + ], + "flags": [ + { + "id": 81027, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "segment_override", + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": 9893 + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "24e4d0fa-6ea5-4773-8abb-44f79048d2a9", + "identifier": "56a8c68b-5015-47dd-97ee-0d727eb16266", + "created_date": "2021-12-15T14:40:00.881184", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_56a8c68b-5015-47dd-97ee-0d727eb16266", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 78 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103709 + }, + "response": { + "traits": [ + { + "id": 26678336, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678337, + "trait_key": "age", + "trait_value": 78 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "5de2cf7f-93f4-4d08-8aa3-381d9b1e3d42", + "identifier": "8e660bf8-cffa-46e3-878a-111627965710", + "created_date": "2021-12-15T14:40:00.881190", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_8e660bf8-cffa-46e3-878a-111627965710", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 44 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103710 + }, + "response": { + "traits": [ + { + "id": 26678338, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678339, + "trait_key": "age", + "trait_value": 44 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "febef74c-1a54-4ca6-83c5-e205a8b570e2", + "identifier": "269c4565-50fa-4e4d-9d1b-e349545c9b1b", + "created_date": "2021-12-15T14:40:00.881196", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_269c4565-50fa-4e4d-9d1b-e349545c9b1b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 56 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103712 + }, + "response": { + "traits": [ + { + "id": 26678340, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678341, + "trait_key": "age", + "trait_value": 56 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "5077957d-8af4-4400-835d-8859017d4f19", + "identifier": "fe0b7a97-f9f9-4ec9-b1d8-142939493321", + "created_date": "2021-12-15T14:40:00.881202", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_fe0b7a97-f9f9-4ec9-b1d8-142939493321", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 56 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103714 + }, + "response": { + "traits": [ + { + "id": 26678342, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678343, + "trait_key": "age", + "trait_value": 56 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "6b06b383-bef7-40b6-9eb6-c94868b4e8f1", + "identifier": "efb574f7-091b-45fa-800d-ebec477efb51", + "created_date": "2021-12-15T14:40:00.881208", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_efb574f7-091b-45fa-800d-ebec477efb51", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 29 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103715 + }, + "response": { + "traits": [ + { + "id": 26678344, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678345, + "trait_key": "age", + "trait_value": 29 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "24ef7912-df97-4c1a-98d4-c9b3c0c294a0", + "identifier": "82cd7c27-6ae9-471e-9b8a-d9829383b489", + "created_date": "2021-12-15T14:40:00.881214", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_82cd7c27-6ae9-471e-9b8a-d9829383b489", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 52 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103716 + }, + "response": { + "traits": [ + { + "id": 26678346, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678347, + "trait_key": "age", + "trait_value": 52 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "77566c33-28ab-4e89-9eb0-782fc26aebeb", + "identifier": "727ae8b6-f421-453c-9310-408150fbe28c", + "created_date": "2021-12-15T14:40:00.881220", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_727ae8b6-f421-453c-9310-408150fbe28c", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 66 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103718 + }, + "response": { + "traits": [ + { + "id": 26678348, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678349, + "trait_key": "age", + "trait_value": 66 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "d27a61ad-300f-4f4c-b88f-d9c8b4eabdce", + "identifier": "b3305fe0-77ac-4a1b-995e-94c413c686d0", + "created_date": "2021-12-15T14:40:00.881226", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b3305fe0-77ac-4a1b-995e-94c413c686d0", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 24 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103719 + }, + "response": { + "traits": [ + { + "id": 26678350, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678351, + "trait_key": "age", + "trait_value": 24 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "e3331902-c64e-49df-a1fc-a07226991f0c", + "identifier": "c99e2bda-f55d-4964-bdd2-80ecfd00297d", + "created_date": "2021-12-15T14:40:00.881232", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c99e2bda-f55d-4964-bdd2-80ecfd00297d", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 75 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103722 + }, + "response": { + "traits": [ + { + "id": 26678352, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678353, + "trait_key": "age", + "trait_value": 75 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "fa599660-3914-465b-b2f4-b363fa9cd3c2", + "identifier": "67476160-7c89-4d5c-bc1a-22ef4a8b2168", + "created_date": "2021-12-15T14:40:00.881238", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_67476160-7c89-4d5c-bc1a-22ef4a8b2168", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 88 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103724 + }, + "response": { + "traits": [ + { + "id": 26678354, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678355, + "trait_key": "age", + "trait_value": 88 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "dcffa2e6-c6d5-41c0-a7d4-5123dd6f6f0e", + "identifier": "b1cc98db-4e99-4f2c-a364-ef6382864188", + "created_date": "2021-12-15T14:40:00.881244", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b1cc98db-4e99-4f2c-a364-ef6382864188", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 12 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103725 + }, + "response": { + "traits": [ + { + "id": 26678356, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678357, + "trait_key": "age", + "trait_value": 12 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "70fdb139-3a53-46ae-8da3-ad0a3ab62313", + "identifier": "11586d45-02f1-48ac-b640-741447251909", + "created_date": "2021-12-15T14:40:00.881249", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_11586d45-02f1-48ac-b640-741447251909", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 22 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103727 + }, + "response": { + "traits": [ + { + "id": 26678359, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678360, + "trait_key": "age", + "trait_value": 22 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "032abbac-93de-4ae0-b2ef-41695bc28fa7", + "identifier": "9515c224-5adc-4e44-bc39-21942779c323", + "created_date": "2021-12-15T14:40:00.881255", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_9515c224-5adc-4e44-bc39-21942779c323", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 83 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103728 + }, + "response": { + "traits": [ + { + "id": 26678363, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678364, + "trait_key": "age", + "trait_value": 83 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "2f85e99a-8685-4ec3-896a-64cf36872c35", + "identifier": "dc6b85e3-e03b-4019-8b6d-97b1d7d25492", + "created_date": "2021-12-15T14:40:00.881261", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_dc6b85e3-e03b-4019-8b6d-97b1d7d25492", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 47 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103730 + }, + "response": { + "traits": [ + { + "id": 26678365, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678366, + "trait_key": "age", + "trait_value": 47 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "3da8f9a1-c795-4d66-babf-39f22432556e", + "identifier": "70f674c4-0474-46aa-ac39-0d7a373fafca", + "created_date": "2021-12-15T14:40:00.881267", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_70f674c4-0474-46aa-ac39-0d7a373fafca", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 62 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103731 + }, + "response": { + "traits": [ + { + "id": 26678367, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678368, + "trait_key": "age", + "trait_value": 62 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "dbb45f9e-a894-4acd-8127-fe0a370468be", + "identifier": "85457200-feeb-468a-91ac-e6397254429a", + "created_date": "2021-12-15T14:40:00.881273", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_85457200-feeb-468a-91ac-e6397254429a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 60 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103733 + }, + "response": { + "traits": [ + { + "id": 26678369, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678370, + "trait_key": "age", + "trait_value": 60 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c04d3ee7-1044-4d88-8deb-8e6ad4020d1b", + "identifier": "46e87d76-34ca-410d-ac4c-67400770c398", + "created_date": "2021-12-15T14:40:00.881279", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_46e87d76-34ca-410d-ac4c-67400770c398", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 64 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103735 + }, + "response": { + "traits": [ + { + "id": 26678371, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678372, + "trait_key": "age", + "trait_value": 64 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "f9590820-76bb-4979-8ee8-cb31a1c800af", + "identifier": "ff74f26a-e832-465b-a165-375b1f70905a", + "created_date": "2021-12-15T14:40:00.881287", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_ff74f26a-e832-465b-a165-375b1f70905a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 33 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103737 + }, + "response": { + "traits": [ + { + "id": 26678374, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678375, + "trait_key": "age", + "trait_value": 33 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "5c7e29fa-e380-48e6-b721-f7b47a329966", + "identifier": "c2ff801e-e145-411d-ba68-9dd2b9871bfe", + "created_date": "2021-12-15T14:40:00.881293", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c2ff801e-e145-411d-ba68-9dd2b9871bfe", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 97 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103738 + }, + "response": { + "traits": [ + { + "id": 26678376, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678377, + "trait_key": "age", + "trait_value": 97 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "5b945288-e15b-43a1-880f-c93ff6f4cffb", + "identifier": "5fd8e83e-bd87-42e7-8c2a-fd31960feb72", + "created_date": "2021-12-15T14:40:00.881299", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_5fd8e83e-bd87-42e7-8c2a-fd31960feb72", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 8 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103739 + }, + "response": { + "traits": [ + { + "id": 26678378, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678379, + "trait_key": "age", + "trait_value": 8 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "380a4595-2d3d-4d3c-aecd-861a4ff1b05f", + "identifier": "2dbbc953-31b3-4bf4-9f63-a09bd37baf78", + "created_date": "2021-12-15T14:40:00.881304", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2dbbc953-31b3-4bf4-9f63-a09bd37baf78", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 85 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103741 + }, + "response": { + "traits": [ + { + "id": 26678380, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678381, + "trait_key": "age", + "trait_value": 85 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "3006cc06-24d3-4819-8722-e6e994c6878d", + "identifier": "2af98d3d-be2f-4bee-b7ae-83c53e1b2811", + "created_date": "2021-12-15T14:40:00.881310", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2af98d3d-be2f-4bee-b7ae-83c53e1b2811", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 7 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103743 + }, + "response": { + "traits": [ + { + "id": 26678382, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678383, + "trait_key": "age", + "trait_value": 7 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "e40de32b-bf2b-4ed4-b5a4-a5883a30adb6", + "identifier": "b21bd1e2-bb87-4135-aca7-e30f465de632", + "created_date": "2021-12-15T14:40:00.881316", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b21bd1e2-bb87-4135-aca7-e30f465de632", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 72 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103744 + }, + "response": { + "traits": [ + { + "id": 26678384, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678385, + "trait_key": "age", + "trait_value": 72 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "10c294e0-06b2-47b8-96c9-842a9d19410e", + "identifier": "96fbbd8f-b5f4-4267-a2db-9f6848dcb20a", + "created_date": "2021-12-15T14:40:00.881322", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_96fbbd8f-b5f4-4267-a2db-9f6848dcb20a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 72 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103746 + }, + "response": { + "traits": [ + { + "id": 26678386, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678387, + "trait_key": "age", + "trait_value": 72 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c5f06308-bf71-4f47-bcd1-baee81e9f0db", + "identifier": "b8f06d73-0430-438d-b788-d91851449908", + "created_date": "2021-12-15T14:40:00.881328", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b8f06d73-0430-438d-b788-d91851449908", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 33 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103747 + }, + "response": { + "traits": [ + { + "id": 26678388, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678389, + "trait_key": "age", + "trait_value": 33 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "1d48c04d-879e-4554-a0bf-c50638ea7945", + "identifier": "430f2a5c-dc93-497f-be0c-859687126d95", + "created_date": "2021-12-15T14:40:00.881334", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_430f2a5c-dc93-497f-be0c-859687126d95", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 97 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103748 + }, + "response": { + "traits": [ + { + "id": 26678390, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678391, + "trait_key": "age", + "trait_value": 97 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "3c9392ec-4c55-45e9-a8ee-60f6e1cd053f", + "identifier": "c3483e1f-ac4e-4e1e-b398-bedde811f441", + "created_date": "2021-12-15T14:40:00.881339", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c3483e1f-ac4e-4e1e-b398-bedde811f441", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 98 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103750 + }, + "response": { + "traits": [ + { + "id": 26678392, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678393, + "trait_key": "age", + "trait_value": 98 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "264fd0b7-d2ac-499b-8cb2-d5e321f28fea", + "identifier": "65e8ea3f-6f3f-4eee-8ad5-30c7a7c7bfe4", + "created_date": "2021-12-15T14:40:00.881345", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_65e8ea3f-6f3f-4eee-8ad5-30c7a7c7bfe4", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 16 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103754 + }, + "response": { + "traits": [ + { + "id": 26678394, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678395, + "trait_key": "age", + "trait_value": 16 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c3adcad5-cee3-4c9b-a1bd-204767c426ac", + "identifier": "cbaa7fae-9453-448a-bff1-d571be7c8a6b", + "created_date": "2021-12-15T14:40:00.881351", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_cbaa7fae-9453-448a-bff1-d571be7c8a6b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 76 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103757 + }, + "response": { + "traits": [ + { + "id": 26678396, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678397, + "trait_key": "age", + "trait_value": 76 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "1e4962d0-8dbe-48cf-a5a2-f91a3329d665", + "identifier": "3ecde417-838e-4469-90a9-d7e925200b51", + "created_date": "2021-12-15T14:40:00.881357", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3ecde417-838e-4469-90a9-d7e925200b51", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 46 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103760 + }, + "response": { + "traits": [ + { + "id": 26678398, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678399, + "trait_key": "age", + "trait_value": 46 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c9e9802c-1bfc-478e-8a13-48f4db8c4780", + "identifier": "555bb037-cc46-47de-b0fa-4bcab906f5e7", + "created_date": "2021-12-15T14:40:00.881362", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_555bb037-cc46-47de-b0fa-4bcab906f5e7", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 97 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103761 + }, + "response": { + "traits": [ + { + "id": 26678400, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678401, + "trait_key": "age", + "trait_value": 97 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "814cc5e7-d6e6-4cab-9f0d-2e023816bd2e", + "identifier": "57fd428e-b41c-4e5f-b47d-de9faed376e3", + "created_date": "2021-12-15T14:40:00.881368", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_57fd428e-b41c-4e5f-b47d-de9faed376e3", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 80 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103763 + }, + "response": { + "traits": [ + { + "id": 26678402, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678403, + "trait_key": "age", + "trait_value": 80 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "a56babd1-7c0d-4f29-ad0f-99905bc993a4", + "identifier": "933949d7-b731-4f3a-a2dc-3d83d0beb1ea", + "created_date": "2021-12-15T14:40:00.881374", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_933949d7-b731-4f3a-a2dc-3d83d0beb1ea", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 88 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103764 + }, + "response": { + "traits": [ + { + "id": 26678404, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678405, + "trait_key": "age", + "trait_value": 88 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "65571c7a-ff3c-45f9-9760-ba25d7460e9c", + "identifier": "a78cf315-d2d8-4d04-b075-e9aba7421706", + "created_date": "2021-12-15T14:40:00.881380", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_a78cf315-d2d8-4d04-b075-e9aba7421706", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 68 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103768 + }, + "response": { + "traits": [ + { + "id": 26678406, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678407, + "trait_key": "age", + "trait_value": 68 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "ad2cb625-4d07-4af6-9eba-18a7b3841fe8", + "identifier": "0d0eb3b4-aab5-4a2e-b82a-47e84c57c64d", + "created_date": "2021-12-15T14:40:00.881386", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_0d0eb3b4-aab5-4a2e-b82a-47e84c57c64d", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 28 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103770 + }, + "response": { + "traits": [ + { + "id": 26678408, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678409, + "trait_key": "age", + "trait_value": 28 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "4a9bb0c3-78e3-42ba-9389-c9d7e60606af", + "identifier": "7edcfe01-784c-4951-8c22-5f84f0569381", + "created_date": "2021-12-15T14:40:00.881392", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7edcfe01-784c-4951-8c22-5f84f0569381", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 47 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103775 + }, + "response": { + "traits": [ + { + "id": 26678410, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678411, + "trait_key": "age", + "trait_value": 47 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "d7f49884-6c09-4072-879e-2739e819b93a", + "identifier": "c334969d-25bd-4ea2-9cd3-634fecdc542d", + "created_date": "2021-12-15T14:40:00.881398", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c334969d-25bd-4ea2-9cd3-634fecdc542d", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 50 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103778 + }, + "response": { + "traits": [ + { + "id": 26678412, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678413, + "trait_key": "age", + "trait_value": 50 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "e518ad76-3358-41cc-a754-fa94ef3a9326", + "identifier": "28501e08-e978-4336-9ddd-d90d87983ab3", + "created_date": "2021-12-15T14:40:00.881404", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_28501e08-e978-4336-9ddd-d90d87983ab3", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 43 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103779 + }, + "response": { + "traits": [ + { + "id": 26678414, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678415, + "trait_key": "age", + "trait_value": 43 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "72cba3cd-0d49-4ba2-988e-cdbcda0190a8", + "identifier": "1b33fc3f-3c0e-480c-acce-1937779c743b", + "created_date": "2021-12-15T14:40:00.881410", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_1b33fc3f-3c0e-480c-acce-1937779c743b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 4 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103782 + }, + "response": { + "traits": [ + { + "id": 26678416, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678417, + "trait_key": "age", + "trait_value": 4 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "9deeec31-7e48-4916-a788-2690f7bb6a67", + "identifier": "2269ea5c-4509-4b7e-acd8-1f7763837464", + "created_date": "2021-12-15T14:40:00.881417", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2269ea5c-4509-4b7e-acd8-1f7763837464", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 14 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103784 + }, + "response": { + "traits": [ + { + "id": 26678418, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678419, + "trait_key": "age", + "trait_value": 14 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "07d47ed2-dc53-4966-b3f4-c1f2646cdf1d", + "identifier": "a4bc3ba0-7366-4bf2-b309-37baf2d0f45f", + "created_date": "2021-12-15T14:40:00.881423", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_a4bc3ba0-7366-4bf2-b309-37baf2d0f45f", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 62 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103786 + }, + "response": { + "traits": [ + { + "id": 26678420, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678421, + "trait_key": "age", + "trait_value": 62 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "ae780a18-9c46-4791-b455-6c33ac560257", + "identifier": "1969664e-a236-46e7-91af-84dca50a313b", + "created_date": "2021-12-15T14:40:00.881428", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_1969664e-a236-46e7-91af-84dca50a313b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 43 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103787 + }, + "response": { + "traits": [ + { + "id": 26678422, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678423, + "trait_key": "age", + "trait_value": 43 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "5756015d-720f-485d-8816-027de60a7680", + "identifier": "7137c59d-0bc0-43d2-b1ad-492b0a03aa85", + "created_date": "2021-12-15T14:40:00.881434", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7137c59d-0bc0-43d2-b1ad-492b0a03aa85", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 52 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103790 + }, + "response": { + "traits": [ + { + "id": 26678427, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678428, + "trait_key": "age", + "trait_value": 52 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "a2137b00-8448-44bd-9c57-ef894cdcc974", + "identifier": "f8fe67d7-958e-452c-a4d4-8249c8b9369c", + "created_date": "2021-12-15T14:40:00.881440", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_f8fe67d7-958e-452c-a4d4-8249c8b9369c", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 67 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103791 + }, + "response": { + "traits": [ + { + "id": 26678429, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678430, + "trait_key": "age", + "trait_value": 67 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "9a6fd956-9984-4584-8071-6a4d801cbd7b", + "identifier": "d2a57b07-3ee1-4b0a-8cd9-e572d14635ce", + "created_date": "2021-12-15T14:40:00.881445", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d2a57b07-3ee1-4b0a-8cd9-e572d14635ce", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 90 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103792 + }, + "response": { + "traits": [ + { + "id": 26678431, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678432, + "trait_key": "age", + "trait_value": 90 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "f921a860-788b-4a5d-8074-e683b924cf0d", + "identifier": "65190952-1717-454b-bef2-b38ea62837c7", + "created_date": "2021-12-15T14:40:00.881450", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_65190952-1717-454b-bef2-b38ea62837c7", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 64 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103794 + }, + "response": { + "traits": [ + { + "id": 26678433, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678434, + "trait_key": "age", + "trait_value": 64 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "a71ee7df-89a6-48be-8307-231361e5010e", + "identifier": "fb098dba-4be6-4117-b95a-fd930c1598b0", + "created_date": "2021-12-15T14:40:00.881456", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_fb098dba-4be6-4117-b95a-fd930c1598b0", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 65 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103796 + }, + "response": { + "traits": [ + { + "id": 26678435, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678436, + "trait_key": "age", + "trait_value": 65 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "69d09c74-b19a-442a-8061-c7b0641b5642", + "identifier": "3e06036d-fa99-4b46-a843-9bd5b1cdf171", + "created_date": "2021-12-15T14:40:00.881462", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3e06036d-fa99-4b46-a843-9bd5b1cdf171", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 51 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103797 + }, + "response": { + "traits": [ + { + "id": 26678437, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678438, + "trait_key": "age", + "trait_value": 51 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "f3b604bb-63f5-4b9f-bf41-b6584e7cccac", + "identifier": "29f66219-8344-4df4-a294-92efb44db0c5", + "created_date": "2021-12-15T14:40:00.881467", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_29f66219-8344-4df4-a294-92efb44db0c5", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 97 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103798 + }, + "response": { + "traits": [ + { + "id": 26678439, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678440, + "trait_key": "age", + "trait_value": 97 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "f7c290ed-649a-4ac6-9832-1f415baac78d", + "identifier": "1ccf1600-ca87-47f0-8cd9-225f9f8389a6", + "created_date": "2021-12-15T14:40:00.881473", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_1ccf1600-ca87-47f0-8cd9-225f9f8389a6", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 76 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103799 + }, + "response": { + "traits": [ + { + "id": 26678441, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678442, + "trait_key": "age", + "trait_value": 76 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "98ed8afd-e03d-4706-9443-55650ebc146a", + "identifier": "4f5a88b9-2b1b-4c0a-9f9f-a3fbeda05dfb", + "created_date": "2021-12-15T14:40:00.881479", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_4f5a88b9-2b1b-4c0a-9f9f-a3fbeda05dfb", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 68 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103800 + }, + "response": { + "traits": [ + { + "id": 26678443, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678444, + "trait_key": "age", + "trait_value": 68 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "89174521-10de-480f-a330-7051d1fbf30a", + "identifier": "742956df-236e-4cc9-8b55-634a7b1da4af", + "created_date": "2021-12-15T14:40:00.881505", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_742956df-236e-4cc9-8b55-634a7b1da4af", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 37 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103802 + }, + "response": { + "traits": [ + { + "id": 26678445, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678446, + "trait_key": "age", + "trait_value": 37 + } + ], + "flags": [ + { + "id": 81027, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "segment_override", + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": 9893 + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "bee25dd0-765b-4451-85aa-977a0294b3d1", + "identifier": "923649a9-5850-4227-a965-32d34ebf9769", + "created_date": "2021-12-15T14:40:00.881511", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_923649a9-5850-4227-a965-32d34ebf9769", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 4 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103803 + }, + "response": { + "traits": [ + { + "id": 26678447, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678448, + "trait_key": "age", + "trait_value": 4 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "e95c0f65-6338-445d-9a5e-31cc10ed072c", + "identifier": "233de9e2-df63-49ca-9f5a-dca000db568d", + "created_date": "2021-12-15T14:40:00.881517", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_233de9e2-df63-49ca-9f5a-dca000db568d", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 19 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103804 + }, + "response": { + "traits": [ + { + "id": 26678449, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678450, + "trait_key": "age", + "trait_value": 19 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "b984486a-81ea-4ff9-8d4e-865b1e69fdc4", + "identifier": "2b051612-8a49-4e04-9500-5daedb8fec88", + "created_date": "2021-12-15T14:40:00.881523", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2b051612-8a49-4e04-9500-5daedb8fec88", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 99 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103805 + }, + "response": { + "traits": [ + { + "id": 26678451, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678452, + "trait_key": "age", + "trait_value": 99 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "6f498939-34ef-4857-a575-e1411aeee122", + "identifier": "d73a7a70-a8b4-4f98-978a-ebd08cbf2542", + "created_date": "2021-12-15T14:40:00.881529", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d73a7a70-a8b4-4f98-978a-ebd08cbf2542", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 58 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103806 + }, + "response": { + "traits": [ + { + "id": 26678453, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678454, + "trait_key": "age", + "trait_value": 58 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "e83f2397-43de-4b2f-ba5b-6ead257b4d52", + "identifier": "d9b9b9e5-36aa-406e-bda6-71cb99be60f5", + "created_date": "2021-12-15T14:40:00.881535", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d9b9b9e5-36aa-406e-bda6-71cb99be60f5", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "trait_key": "age", + "trait_value": 28 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103808 + }, + "response": { + "traits": [ + { + "id": 26678455, + "trait_key": "favourite_colour", + "trait_value": "orange" + }, + { + "id": 26678456, + "trait_key": "age", + "trait_value": 28 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "1ab52980-b736-4207-bd0b-d068c6e78e83", + "identifier": "560cdbac-dfd9-4536-b65b-6654d575058a", + "created_date": "2021-12-15T14:40:00.881541", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_560cdbac-dfd9-4536-b65b-6654d575058a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 85 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103811 + }, + "response": { + "traits": [ + { + "id": 26678457, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678458, + "trait_key": "age", + "trait_value": 85 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "65a9c511-177d-4d20-9dfb-6771efeb71f9", + "identifier": "be3348ec-6fd9-4b6d-a86a-fd69600855b2", + "created_date": "2021-12-15T14:40:00.881546", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_be3348ec-6fd9-4b6d-a86a-fd69600855b2", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 9 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103812 + }, + "response": { + "traits": [ + { + "id": 26678459, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678460, + "trait_key": "age", + "trait_value": 9 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "45dbc669-d3ba-45cc-b31e-67a4db3a9ea7", + "identifier": "0cfd0d72-4de4-4ed7-9cfb-d80dc3dacead", + "created_date": "2021-12-15T14:40:00.881552", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_0cfd0d72-4de4-4ed7-9cfb-d80dc3dacead", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 47 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103813 + }, + "response": { + "traits": [ + { + "id": 26678461, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678462, + "trait_key": "age", + "trait_value": 47 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "baz", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "79a61937-84b0-400a-b4c3-d5e4a0c61e85", + "identifier": "93f06180-cee7-428e-8385-1206895e4313", + "created_date": "2021-12-15T14:40:00.881557", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_93f06180-cee7-428e-8385-1206895e4313", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 42 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103814 + }, + "response": { + "traits": [ + { + "id": 26678463, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678464, + "trait_key": "age", + "trait_value": 42 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "18e33321-bb8b-4ed0-ab00-e01a19f64071", + "identifier": "18edb157-34cc-4896-aa35-76a7ee68fe68", + "created_date": "2021-12-15T14:40:00.881563", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_18edb157-34cc-4896-aa35-76a7ee68fe68", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 46 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103815 + }, + "response": { + "traits": [ + { + "id": 26678465, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678466, + "trait_key": "age", + "trait_value": 46 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "35596db0-cad3-4b34-8171-cb09b7576305", + "identifier": "e7656d90-7da5-4ce1-b647-36cd977d58fa", + "created_date": "2021-12-15T14:40:00.881568", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_e7656d90-7da5-4ce1-b647-36cd977d58fa", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 34 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103817 + }, + "response": { + "traits": [ + { + "id": 26678467, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678468, + "trait_key": "age", + "trait_value": 34 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "71c30607-114b-47cf-b956-33b2d190cbe2", + "identifier": "d5a54a43-625b-4878-b3fa-120a2bfdd86e", + "created_date": "2021-12-15T14:40:00.881574", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d5a54a43-625b-4878-b3fa-120a2bfdd86e", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 56 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103818 + }, + "response": { + "traits": [ + { + "id": 26678469, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678470, + "trait_key": "age", + "trait_value": 56 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "1746ccce-f02f-410f-83ad-03856ceeeceb", + "identifier": "23edd289-5188-4af0-b0bf-64c42f73f2f4", + "created_date": "2021-12-15T14:40:00.881579", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_23edd289-5188-4af0-b0bf-64c42f73f2f4", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "trait_key": "age", + "trait_value": 77 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103819 + }, + "response": { + "traits": [ + { + "id": 26678471, + "trait_key": "favourite_colour", + "trait_value": "yellow" + }, + { + "id": 26678472, + "trait_key": "age", + "trait_value": 77 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "1a441f46-8d4b-4a81-9b42-ba5b392f20c9", + "identifier": "41f0b1f5-93a1-43c0-afb7-bce9dc20aac0", + "created_date": "2021-12-15T14:40:00.881585", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_41f0b1f5-93a1-43c0-afb7-bce9dc20aac0", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 48 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103820 + }, + "response": { + "traits": [ + { + "id": 26678473, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678474, + "trait_key": "age", + "trait_value": 48 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "8357857d-6166-4f7c-ac9c-6af97f703c3e", + "identifier": "d3f16e64-9cf8-477c-a09b-7b60723c1694", + "created_date": "2021-12-15T14:40:00.881591", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d3f16e64-9cf8-477c-a09b-7b60723c1694", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "trait_key": "age", + "trait_value": 62 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103821 + }, + "response": { + "traits": [ + { + "id": 26678475, + "trait_key": "favourite_colour", + "trait_value": "green" + }, + { + "id": 26678476, + "trait_key": "age", + "trait_value": 62 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "d4ae7c03-814f-41f2-a6de-5a28ce044770", + "identifier": "957d39a5-6e97-4026-9d94-be68aa97bf1b", + "created_date": "2021-12-15T14:40:00.881596", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_957d39a5-6e97-4026-9d94-be68aa97bf1b", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 30 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103822 + }, + "response": { + "traits": [ + { + "id": 26678477, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678478, + "trait_key": "age", + "trait_value": 30 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "7e6dabdf-9e65-4949-8dd4-21fe0c297855", + "identifier": "53273d70-2f37-4c43-8979-e0426f7ac375", + "created_date": "2021-12-15T14:40:00.881602", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_53273d70-2f37-4c43-8979-e0426f7ac375", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 89 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103823 + }, + "response": { + "traits": [ + { + "id": 26678479, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678480, + "trait_key": "age", + "trait_value": 89 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "a050d1a1-d53a-49ad-b5a9-91ac82bb66c7", + "identifier": "4ab15967-c00b-4a6b-8da6-0a9ef67683fd", + "created_date": "2021-12-15T14:40:00.881607", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_4ab15967-c00b-4a6b-8da6-0a9ef67683fd", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "trait_key": "age", + "trait_value": 92 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103824 + }, + "response": { + "traits": [ + { + "id": 26678481, + "trait_key": "favourite_colour", + "trait_value": "blue" + }, + { + "id": 26678482, + "trait_key": "age", + "trait_value": 92 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + }, + { + "identity": { + "identity_uuid": "c6518ef6-1b38-4d01-a058-e98f701f6253", + "identifier": "2448af3b-bf5c-493b-9bce-13be5d6e697a", + "created_date": "2021-12-15T14:40:00.881614", + "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2448af3b-bf5c-493b-9bce-13be5d6e697a", + "identity_features": [], + "identity_traits": [ + { + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "trait_key": "age", + "trait_value": 43 + } + ], + "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", + "django_id": 32103825 + }, + "response": { + "traits": [ + { + "id": 26678483, + "trait_key": "favourite_colour", + "trait_value": "red" + }, + { + "id": 26678484, + "trait_key": "age", + "trait_value": 43 + } + ], + "flags": [ + { + "id": 78978, + "feature": { + "id": 15058, + "name": "string_feature", + "created_date": "2021-11-29T17:15:51.694223Z", + "description": null, + "initial_value": "foo", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": "foo", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78980, + "feature": { + "id": 15059, + "name": "integer_feature", + "created_date": "2021-11-29T17:16:11.288134Z", + "description": null, + "initial_value": "1234", + "default_enabled": true, + "type": "STANDARD" + }, + "feature_state_value": 1234, + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78982, + "feature": { + "id": 15060, + "name": "basic_flag", + "created_date": "2021-11-29T17:16:25.449058Z", + "description": null, + "initial_value": null, + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": null, + "enabled": false, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78984, + "feature": { + "id": 15061, + "name": "float_feature", + "created_date": "2021-11-29T17:16:43.961385Z", + "description": null, + "initial_value": "12.34", + "default_enabled": false, + "type": "STANDARD" + }, + "feature_state_value": "12.34", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + }, + { + "id": 78986, + "feature": { + "id": 15062, + "name": "mv_feature", + "created_date": "2021-11-29T17:17:23.645334Z", + "description": null, + "initial_value": "foo", + "default_enabled": false, + "type": "MULTIVARIATE" + }, + "feature_state_value": "bar", + "enabled": true, + "environment": 12561, + "identity": null, + "feature_segment": null + } + ] + } + } + ] +} \ No newline at end of file diff --git a/tests/engine-tests/engine-test-data/readme.md b/tests/engine-tests/engine-test-data/readme.md new file mode 100644 index 0000000..64002cd --- /dev/null +++ b/tests/engine-tests/engine-test-data/readme.md @@ -0,0 +1,30 @@ +# Engine Test Data + +This repository contains a single directory containing json files that can be used to test that any Flagsmith engine +written in a given language is correct. + +Each JSON file should consist of a single object in the following format. + +```json +{ + "environment": {...}, // the environment document as found in DynamoDB + "identities_and_responses": [ + { + "identity": {...}, // the identity as found in DynamoDB, + "response": {...}, // the response that was obtained from the current API + } + ] +} +``` + +To use this data, you will need to write a test case in the repository which contains the engine code and include +this repository as a submodule to get access to the json files. + +To add the git submodule: + +```bash +git submodule add git@github.com:Flagsmith/engine-test-data.git tests/engine_tests/engine-test-data +``` + +An example of how to use the test data can be found in the flagsmith-flag-engine repository +[here](https://github.com/Flagsmith/flagsmith-engine/blob/main/tests/engine_tests/test_engine.py). diff --git a/tests/engine-tests/engine.test.ts b/tests/engine-tests/engine.test.ts new file mode 100644 index 0000000..834e416 --- /dev/null +++ b/tests/engine-tests/engine.test.ts @@ -0,0 +1,52 @@ +import { readFileSync } from 'fs'; +import { getIdentityFeatureStates } from '../../flagsmith-engine'; +import { EnvironmentModel } from '../../flagsmith-engine/environments/models'; +import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util'; +import { IdentityModel } from '../../flagsmith-engine/identities/models'; +import { buildIdentityModel } from '../../flagsmith-engine/identities/util'; +import { identityInSegment } from '../unit/utils'; + +function extractTestCases( + filePath: string +): { + environment: EnvironmentModel; + identity: IdentityModel; + response: any; +}[] { + const data = JSON.parse(readFileSync(filePath, 'utf-8')); + const environmentModel = buildEnvironmentModel(data['environment']); + const test_data = data['identities_and_responses'].map((test_case: any) => { + const identity = buildIdentityModel(test_case['identity']); + + return { + environment: environmentModel, + identity: identity, + response: test_case['response'] + }; + }); + return test_data; +} + +test('Test Engine', () => { + const testCases = extractTestCases( + __dirname + '/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json' + ); + for (const testCase of testCases) { + const engine_response = getIdentityFeatureStates(testCase.environment, testCase.identity); + const sortedEngineFlags = engine_response.sort((a, b) => + a.feature.name > b.feature.name ? 1 : -1 + ); + const sortedAPIFlags = testCase.response['flags'].sort((a: any, b: any) => + a.feature.name > b.feature.name ? 1 : -1 + ); + + expect(sortedEngineFlags.length).toBe(sortedAPIFlags.length); + + for (let i = 0; i < sortedEngineFlags.length; i++) { + expect(sortedEngineFlags[i].getValue(testCase.identity.djangoID)).toBe( + sortedAPIFlags[i]['feature_state_value'] + ); + expect(sortedEngineFlags[i].enabled).toBe(sortedAPIFlags[i]['enabled']); + } + } +}); diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/egine.test.ts b/tests/unit/egine.test.ts new file mode 100644 index 0000000..3f6614f --- /dev/null +++ b/tests/unit/egine.test.ts @@ -0,0 +1,96 @@ +import { + getEnvironmentFeatureState, + getEnvironmentFeatureStates, + getIdentityFeatureState, + getIdentityFeatureStates +} from '../../flagsmith-engine'; +import { CONSTANTS } from '../../flagsmith-engine/features/constants'; +import { FeatureModel, FeatureStateModel } from '../../flagsmith-engine/features/models'; +import { TraitModel } from '../../flagsmith-engine/identities/traits/models'; +import { + environment, + environmentWithSegmentOverride, + feature1, + getEnvironmentFeatureStateForFeature, + getEnvironmentFeatureStateForFeatureByName, + identity, + identityInSegment, + segmentConditionProperty, + segmentConditionStringValue +} from './utils'; + +test('test_identity_get_feature_state_without_any_override', () => { + const feature_state = getIdentityFeatureState(environment(), identity(), feature1().name); + + expect(feature_state.feature).toStrictEqual(feature1()); +}); + +test('test_identity_get_all_feature_states_no_segments', () => { + const env = environment(); + const ident = identity(); + const overridden_feature = new FeatureModel(3, 'overridden_feature', CONSTANTS.STANDARD); + + env.featureStates.push(new FeatureStateModel(overridden_feature, false, 3)); + + ident.identityFeatures = [new FeatureStateModel(overridden_feature, true, 4)]; + + const featureStates = getIdentityFeatureStates(env, ident); + + expect(featureStates.length).toBe(3); + for (const featuresState of featureStates) { + const environmentFeatureState = getEnvironmentFeatureStateForFeature( + env, + featuresState.feature + ); + const expected = + environmentFeatureState?.feature == overridden_feature + ? true + : environmentFeatureState?.enabled; + expect(featuresState.enabled).toBe(expected); + } +}); + +test('test_identity_get_all_feature_states_with_traits', () => { + const trait_models = new TraitModel(segmentConditionProperty, segmentConditionStringValue); + + const featureStates = getIdentityFeatureStates( + environmentWithSegmentOverride(), + identityInSegment(), + [trait_models] + ); + expect(featureStates[0].getValue()).toBe('segment_override'); +}); + +test('test_environment_get_all_feature_states', () => { + const env = environment(); + const featureStates = getEnvironmentFeatureStates(env); + + expect(featureStates).toBe(env.featureStates); +}); + +test('test_environment_get_feature_states_hides_disabled_flags_if_enabled', () => { + const env = environment(); + + env.project.hideDisabledFlags = true; + + const featureStates = getEnvironmentFeatureStates(env); + + expect(featureStates).not.toBe(env.featureStates); + for (const fs of featureStates) { + expect(fs.enabled).toBe(true); + } +}); + +test('test_environment_get_feature_state', () => { + const env = environment(); + const feature = feature1(); + const featureState = getEnvironmentFeatureState(env, feature.name); + + expect(featureState.feature).toStrictEqual(feature); +}); + +test('test_environment_get_feature_state_raises_feature_state_not_found', () => { + expect(() => { + getEnvironmentFeatureState(environment(), 'not_a_feature_name'); + }).toThrowError('Feature State Not Found'); +}); diff --git a/tests/unit/environments/builder.test.ts b/tests/unit/environments/builder.test.ts new file mode 100644 index 0000000..1960be5 --- /dev/null +++ b/tests/unit/environments/builder.test.ts @@ -0,0 +1,148 @@ +import { EnvironmentModel } from '../../../flagsmith-engine/environments/models'; +import { + buildEnvironmentAPIKeyModel, + buildEnvironmentModel +} from '../../../flagsmith-engine/environments/util'; +import { CONSTANTS } from '../../../flagsmith-engine/features/constants'; +import { + FeatureStateModel, + MultivariateFeatureStateValueModel +} from '../../../flagsmith-engine/features/models'; +import { getEnvironmentFeatureStateForFeatureByName } from '../utils'; + +test('test_get_flags_for_environment_returns_feature_states_for_environment_dictionary', () => { + const stringValue = 'foo'; + const featureWithStringValueName = 'feature_with_string_value'; + + const environmentDict = { + id: 1, + api_key: 'api-key', + project: { + id: 1, + name: 'test project', + organisation: { + id: 1, + name: 'Test Org', + stop_serving_flags: false, + persist_trait_data: true, + feature_analytics: true + }, + hide_disabled_flags: false + }, + feature_states: [ + { + id: 1, + enabled: true, + feature_state_value: undefined, + feature: { id: 1, name: 'enabled_feature', type: CONSTANTS.STANDARD } + }, + { + id: 2, + enabled: false, + feature_state_value: undefined, + feature: { id: 2, name: 'disabled_feature', type: CONSTANTS.STANDARD } + }, + { + id: 3, + enabled: true, + feature_state_value: stringValue, + feature: { + id: 3, + name: featureWithStringValueName, + type: CONSTANTS.STANDARD + } + } + ] + }; + + const environmentModel = buildEnvironmentModel(environmentDict); + + expect(environmentModel).toBeInstanceOf(EnvironmentModel); + expect(environmentModel.featureStates.length).toBe(3); + for (const fs of environmentModel.featureStates) { + expect(fs).toBeInstanceOf(FeatureStateModel); + } + const receivedValue = getEnvironmentFeatureStateForFeatureByName( + environmentModel, + featureWithStringValueName + )?.getValue(); + expect(receivedValue).toBe(stringValue); +}); + +test('test_build_environment_model_with_multivariate_flag', () => { + const variate1Value = 'value-1'; + const variate2Value = 'value-2'; + + const environmentJSON = { + id: 1, + api_key: 'api-key', + project: { + id: 1, + name: 'test project', + organisation: { + id: 1, + name: 'Test Org', + stop_serving_flags: false, + persist_trait_data: true, + feature_analytics: true + }, + hide_disabled_flags: false + }, + feature_states: [ + { + id: 1, + enabled: true, + feature_state_value: undefined, + feature: { + id: 1, + name: 'enabled_feature', + type: CONSTANTS.STANDARD + }, + multivariate_feature_state_values: [ + { + id: 1, + percentage_allocation: 10.0, + multivariate_feature_option: { + value: variate1Value + } + }, + { + id: 2, + percentage_allocation: 10.0, + multivariate_feature_option: { + value: variate2Value, + id: 2 + } + } + ] + } + ] + }; + + const environmentModel = buildEnvironmentModel(environmentJSON); + + expect(environmentModel).toBeInstanceOf(EnvironmentModel); + expect(environmentJSON.feature_states.length).toBe(1); + + const fs = environmentModel.featureStates[0]; + + for (const mvfs of fs.multivariateFeatureStateValues) { + expect(mvfs).toBeInstanceOf(MultivariateFeatureStateValueModel); + } +}); + +test('test_build_environment_api_key_model', () => { + const environmentKeyJSON = { + key: 'ser.7duQYrsasJXqdGsdaagyfU', + active: true, + created_at: '2022-02-07T04:58:25.969438+00:00', + client_api_key: 'RQchaCQ2mYicSCAwKoAg2E', + id: 10, + name: 'api key 2', + expires_at: undefined + }; + + const environmentAPIKeyModel = buildEnvironmentAPIKeyModel(environmentKeyJSON); + + expect(environmentAPIKeyModel.key).toBe(environmentKeyJSON['key']); +}); diff --git a/tests/unit/environments/models.test.ts b/tests/unit/environments/models.test.ts new file mode 100644 index 0000000..20c27a6 --- /dev/null +++ b/tests/unit/environments/models.test.ts @@ -0,0 +1,49 @@ +import { EnvironmentAPIKeyModel } from '../../../flagsmith-engine/environments/models'; + +test('test_environment_api_key_model_is_valid_is_true_for_non_expired_active_key', () => { + const environmentAPIKeyModel = new EnvironmentAPIKeyModel( + 1, + 'ser.random_key', + Date.now(), + 'test_key', + 'test_key' + ); + expect(environmentAPIKeyModel.isValid()).toBe(true); +}); + +test('test_environment_api_key_model_is_valid_is_true_for_non_expired_active_key_with_expired_date_in_future', () => { + const environmentAPIKeyModel = new EnvironmentAPIKeyModel( + 1, + 'ser.random_key', + Date.now(), + 'test_key', + 'test_key', + Date.now() + 1000 * 60 * 60 * 24 * 2 + ); + expect(environmentAPIKeyModel.isValid()).toBe(true); +}); + +test('test_environment_api_key_model_is_valid_is_false_for_expired_active_key', () => { + const environmentAPIKeyModel = new EnvironmentAPIKeyModel( + 1, + 'ser.random_key', + Date.now() - 1000 * 60 * 60 * 24 * 2, + 'test_key', + 'test_key', + Date.now() + ); + expect(environmentAPIKeyModel.isValid()).toBe(false); +}); + +test('test_environment_api_key_model_is_valid_is_false_for_non_expired_inactive_key', () => { + const environmentAPIKeyModel = new EnvironmentAPIKeyModel( + 1, + 'ser.random_key', + Date.now(), + 'test_key', + 'test_key' + ); + + environmentAPIKeyModel.active = false; + expect(environmentAPIKeyModel.isValid()).toBe(false); +}); diff --git a/tests/unit/features/models.test.ts b/tests/unit/features/models.test.ts new file mode 100644 index 0000000..76e762d --- /dev/null +++ b/tests/unit/features/models.test.ts @@ -0,0 +1,72 @@ +import { CONSTANTS } from '../../../flagsmith-engine/features/constants'; +import { + FeatureModel, + FeatureStateModel, + MultivariateFeatureOptionModel, + MultivariateFeatureStateValueModel +} from '../../../flagsmith-engine/features/models'; +import { feature1 } from '../utils'; + +test('test_initializing_feature_state_creates_default_feature_state_uuid', () => { + const featureState = new FeatureStateModel(feature1(), true, 1); + expect(featureState.featurestateUUID).toBeDefined(); +}); + +test('test_initializing_multivariate_feature_state_value_creates_default_uuid', () => { + const mvFeatureOption = new MultivariateFeatureOptionModel('value'); + const mvFsValueModel = new MultivariateFeatureStateValueModel(mvFeatureOption, 10, 1); + + expect(mvFsValueModel.mvFsValueUuid).toBeDefined(); +}); + +test('test_feature_state_get_value_no_mv_values', () => { + const value = 'foo'; + const featureState = new FeatureStateModel(feature1(), true, 1); + + featureState.setValue(value); + + expect(featureState.getValue()).toBe(value); + expect(featureState.getValue(1)).toBe(value); +}); + +test('test_feature_state_get_value_mv_values', () => { + const mvFeatureControlValue = 'control'; + const mvFeatureValue1 = 'foo'; + const mvFeatureValue2 = 'bar'; + + const cases = [ + [10, mvFeatureValue1], + [40, mvFeatureValue2], + [70, mvFeatureControlValue] + ]; + + for (const testCase of cases) { + const myFeature = new FeatureModel(1, 'mv_feature', CONSTANTS.STANDARD); + + const mvFeatureOption1 = new MultivariateFeatureOptionModel(mvFeatureValue1, 1); + const mvFeatureOption2 = new MultivariateFeatureOptionModel(mvFeatureValue2, 2); + + const mvFeatureStateValue1 = new MultivariateFeatureStateValueModel( + mvFeatureOption1, + 30, + 1 + ); + const mvFeatureStateValue2 = new MultivariateFeatureStateValueModel( + mvFeatureOption2, + 30, + 2 + ); + + const mvFeatureState = new FeatureStateModel(myFeature, true, 1); + mvFeatureState.multivariateFeatureStateValues = [ + mvFeatureStateValue1, + mvFeatureStateValue2 + ]; + + mvFeatureState.setValue(mvFeatureControlValue); + + // TODO + // expect(mvFeatureState.getValue(3)).toBe(testCase[1]); + expect(1).toBe(1); + } +}); diff --git a/tests/unit/identities/identities_builders.test.ts b/tests/unit/identities/identities_builders.test.ts new file mode 100644 index 0000000..3c15ce7 --- /dev/null +++ b/tests/unit/identities/identities_builders.test.ts @@ -0,0 +1,85 @@ +import { FeatureStateModel } from '../../../flagsmith-engine/features/models'; +import { IdentityModel } from '../../../flagsmith-engine/identities/models'; +import { buildIdentityModel } from '../../../flagsmith-engine/identities/util'; + +test('test_build_identity_model_from_dictionary_no_feature_states', () => { + const identity = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + identity_traits: [{ trait_key: 'trait_key', trait_value: 'trait_value' }] + }; + + const identityModel = buildIdentityModel(identity); + + expect(identityModel.identityFeatures.length).toBe(0); + expect(identityModel.identityTraits.length).toBe(1); +}); + +test('test_build_identity_model_from_dictionary_uses_identity_feature_list_for_identity_features', () => { + const identity_dict = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + identity_features: [ + { + id: 1, + feature: { + id: 1, + name: 'test_feature', + type: 'STANDARD' + }, + enabled: true, + feature_state_value: 'some-value' + } + ] + }; + + const identityModel = buildIdentityModel(identity_dict); + + expect(identityModel.identityFeatures.length).toBe(1); +}); + +test('test_build_build_identity_model_from_dict_creates_identity_uuid', () => { + const identity_model = buildIdentityModel({ + identifier: 'test_user', + environment_api_key: 'some_key' + }); + expect(identity_model.identityUuid).not.toBe(undefined); +}); + +test('test_build_identity_model_from_dictionary_with_feature_states', () => { + const identity_dict = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + identity_features: [ + { + id: 1, + feature: { + id: 1, + name: 'test_feature', + type: 'STANDARD' + }, + enabled: true, + feature_state_value: 'some-value' + } + ] + }; + + const identityModel = buildIdentityModel(identity_dict); + + expect(identityModel).toBeInstanceOf(IdentityModel); + expect(identityModel.identityFeatures.length).toBe(1); + expect(identityModel.identityFeatures[0]).toBeInstanceOf(FeatureStateModel); +}); + +test('test_identity_dict_created_using_model_can_convert_back_to_model', () => { + const identityModel = new IdentityModel('some_key', [], [], '', ''); + + const identityJSON = JSON.parse(JSON.stringify(identityModel)); + expect(buildIdentityModel(identityJSON)).toBeInstanceOf(IdentityModel); +}); diff --git a/tests/unit/identities/identities_models.test.ts b/tests/unit/identities/identities_models.test.ts new file mode 100644 index 0000000..5aba3a8 --- /dev/null +++ b/tests/unit/identities/identities_models.test.ts @@ -0,0 +1,105 @@ +import { FeatureStateModel } from '../../../flagsmith-engine/features/models'; +import { IdentityModel } from '../../../flagsmith-engine/identities/models'; +import { TraitModel } from '../../../flagsmith-engine/identities/traits/models'; +import { buildIdentityModel } from '../../../flagsmith-engine/identities/util'; +import { feature1, identityInSegment } from '../utils'; + +test('test_composite_key', () => { + const identity = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + identity_traits: [{ trait_key: 'trait_key', trait_value: 'trait_value' }] + }; + + const identityModel = buildIdentityModel(identity); + + expect(identityModel.compositeKey).toBe('api-key_test-identity'); +}); + +test('test_identiy_model_creates_default_identity_uuid', () => { + const identity = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + identity_traits: [{ trait_key: 'trait_key', trait_value: 'trait_value' }] + }; + + const identityModel = buildIdentityModel(identity); + + expect(identityModel.identityUuid).toBeDefined(); +}); + +test('test_generate_composite_key', () => { + const identity = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + identity_traits: [{ trait_key: 'trait_key', trait_value: 'trait_value' }] + }; + + const identityModel = buildIdentityModel(identity); + + expect(IdentityModel.generateCompositeKey('api-key', 'test-identity')).toBe( + 'api-key_test-identity' + ); +}); + +test('test_update_traits_remove_traits_with_none_value', () => { + const ident = identityInSegment(); + + const trait_key = ident.identityTraits[0].traitKey; + const trait_to_remove = new TraitModel(trait_key, undefined); + + ident.update_traits([trait_to_remove]); + + expect(ident.identityTraits.length).toBe(0); +}); + +test('test_update_identity_traits_updates_trait_value', () => { + const identity = identityInSegment(); + + const traitKey = identity.identityTraits[0].traitKey; + const traitValue = 'updated_trait_value'; + const traitToUpdate = new TraitModel(traitKey, traitValue); + + identity.update_traits([traitToUpdate]); + + expect(identity.identityTraits.length).toBe(1); + expect(identity.identityTraits[0]).toBe(traitToUpdate); +}); + +test('test_update_traits_adds_new_traits', () => { + const identity = identityInSegment(); + + const newTrait = new TraitModel('new_key', 'foobar'); + + identity.update_traits([newTrait]); + + expect(identity.identityTraits.length).toBe(2); + expect(identity.identityTraits).toContain(newTrait); +}); + +test('test_append_feature_state', () => { + const ident = identityInSegment(); + + const fs1 = new FeatureStateModel(feature1(), false, 1); + + ident.identityFeatures.push(fs1); + + expect(ident.identityFeatures).toContain(fs1); +}); + +test('test_appending_feature_states_raises_duplicate_feature_state_if_fs_for_the_feature_already_exists', () => { + const ident = identityInSegment(); + + const fs1 = new FeatureStateModel(feature1(), false, 1); + const fs2 = new FeatureStateModel(feature1(), true, 1); + ident.identityFeatures.push(fs1); + expect(() => { + ident.identityFeatures.push(fs2); + }).toThrowError(); +}); diff --git a/tests/unit/organization/models.test.ts b/tests/unit/organization/models.test.ts new file mode 100644 index 0000000..3b12f7b --- /dev/null +++ b/tests/unit/organization/models.test.ts @@ -0,0 +1,12 @@ +import { buildOrganizationModel } from '../../../flagsmith-engine/organisations/util'; + +test('Test builder', () => { + const model = buildOrganizationModel({ + persist_trait_data: true, + name: 'Flagsmith', + feature_analytics: false, + stop_serving_flags: false, + id: 13 + }); + expect(model.unique_slug).toBe('13-Flagsmith'); +}); diff --git a/tests/unit/segments/segments_model.test.ts b/tests/unit/segments/segments_model.test.ts new file mode 100644 index 0000000..1811154 --- /dev/null +++ b/tests/unit/segments/segments_model.test.ts @@ -0,0 +1,101 @@ +import { + ALL_RULE, + ANY_RULE, + CONDITION_OPERATORS, + NONE_RULE +} from '../../../flagsmith-engine/segments/constants'; +import { + all, + any, + SegmentConditionModel, + SegmentRuleModel +} from '../../../flagsmith-engine/segments/models'; + +const conditionMatchCases: [string, string | number | boolean, string, boolean][] = [ + [CONDITION_OPERATORS.EQUAL, 'bar', 'bar', true], + [CONDITION_OPERATORS.EQUAL, 'bar', 'baz', false], + [CONDITION_OPERATORS.EQUAL, 1, '1', true], + [CONDITION_OPERATORS.EQUAL, 1, '2', false], + [CONDITION_OPERATORS.EQUAL, true, 'true', true], + [CONDITION_OPERATORS.EQUAL, false, 'false', true], + [CONDITION_OPERATORS.EQUAL, false, 'true', false], + [CONDITION_OPERATORS.EQUAL, true, 'false', false], + [CONDITION_OPERATORS.EQUAL, 1.23, '1.23', true], + [CONDITION_OPERATORS.EQUAL, 1.23, '4.56', false], + [CONDITION_OPERATORS.GREATER_THAN, 2, '1', true], + [CONDITION_OPERATORS.GREATER_THAN, 1, '1', false], + [CONDITION_OPERATORS.GREATER_THAN, 0, '1', false], + [CONDITION_OPERATORS.GREATER_THAN, 2.1, '2.0', true], + [CONDITION_OPERATORS.GREATER_THAN, 2.1, '2.1', false], + [CONDITION_OPERATORS.GREATER_THAN, 2.0, '2.1', false], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2, '1', true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 1, '1', true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 0, '1', false], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2.1, '2.0', true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2.1, '2.1', true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2.0, '2.1', false], + [CONDITION_OPERATORS.LESS_THAN, 1, '2', true], + [CONDITION_OPERATORS.LESS_THAN, 1, '1', false], + [CONDITION_OPERATORS.LESS_THAN, 1, '0', false], + [CONDITION_OPERATORS.LESS_THAN, 2.0, '2.1', true], + [CONDITION_OPERATORS.LESS_THAN, 2.1, '2.1', false], + [CONDITION_OPERATORS.LESS_THAN, 2.1, '2.0', false], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 1, '2', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 1, '1', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 1, '0', false], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 2.0, '2.1', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 2.1, '2.1', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 2.1, '2.0', false], + [CONDITION_OPERATORS.NOT_EQUAL, 'bar', 'baz', true], + [CONDITION_OPERATORS.NOT_EQUAL, 'bar', 'bar', false], + [CONDITION_OPERATORS.NOT_EQUAL, 1, '2', true], + [CONDITION_OPERATORS.NOT_EQUAL, 1, '1', false], + [CONDITION_OPERATORS.NOT_EQUAL, true, 'false', true], + [CONDITION_OPERATORS.NOT_EQUAL, false, 'true', true], + [CONDITION_OPERATORS.NOT_EQUAL, false, 'false', false], + [CONDITION_OPERATORS.NOT_EQUAL, true, 'true', false], + [CONDITION_OPERATORS.CONTAINS, 'bar', 'b', true], + [CONDITION_OPERATORS.CONTAINS, 'bar', 'bar', true], + [CONDITION_OPERATORS.CONTAINS, 'bar', 'baz', false], + [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'b', false], + [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'bar', false], + [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'baz', true], + [CONDITION_OPERATORS.REGEX, 'foo', '[a-z]+', true], + [CONDITION_OPERATORS.REGEX, 'FOO', '[a-z]+', false] +]; + +test('test_segment_condition_matches_trait_value', () => { + for (const testCase of conditionMatchCases) { + expect( + new SegmentConditionModel(testCase[0], testCase[2], 'foo').matchesTraitValue( + testCase[1] + ) + ).toBe(testCase[3]); + } +}); + +test('test_segment_rule_none', () => { + const testCases: [boolean[], boolean][] = [ + [[], true], + [[false], true], + [[false, false], true], + [[false, true], false], + [[true, true], false] + ]; + + for (const testCase of testCases) { + expect(SegmentRuleModel.none(testCase[0])).toBe(testCase[1]); + } +}); + +test('test_segment_rule_matching_function', () => { + const testCases: [string, CallableFunction][] = [ + [ALL_RULE, all], + [ANY_RULE, any], + [NONE_RULE, SegmentRuleModel.none] + ]; + + for (const testCase of testCases) { + expect(new SegmentRuleModel(testCase[0]).matchingFunction()).toBe(testCase[1]); + } +}); diff --git a/tests/unit/segments/util.ts b/tests/unit/segments/util.ts new file mode 100644 index 0000000..9b35241 --- /dev/null +++ b/tests/unit/segments/util.ts @@ -0,0 +1,151 @@ +import { ALL_RULE, ANY_RULE, EQUAL } from '../../../flagsmith-engine/segments/constants'; +import { SegmentModel } from '../../../flagsmith-engine/segments/models'; +import { buildSegmentModel, buildSegmentRuleModel } from '../../../flagsmith-engine/segments/util'; + +export const traitKey1 = 'email'; +export const traitValue1 = 'user@example.com'; + +export const traitKey2 = 'num_purchase'; +export const traitValue2 = '12'; + +export const traitKey_3 = 'date_joined'; +export const traitValue3 = '2021-01-01'; + +export const emptySegment = new SegmentModel(1, 'empty_segment'); + +export const segmentSingleCondition = buildSegmentModel({ + id: 2, + name: 'segment_one_condition', + rules: [ + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey1, + value: traitValue1 + } + ] + } + ] +}); + +export const segmentMultipleConditionsAll = buildSegmentModel({ + id: 3, + name: 'segment_multiple_conditions_all', + rules: [ + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey1, + value: traitValue1 + }, + { + operator: EQUAL, + property_: traitKey2, + value: traitValue2 + } + ] + } + ] +}); + +export const segmentMultipleConditionsAny = buildSegmentModel({ + id: 4, + name: 'segment_multiple_conditions_any', + rules: [ + { + type: ANY_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey1, + value: traitValue1 + }, + { + operator: EQUAL, + property_: traitKey2, + value: traitValue2 + } + ] + } + ] +}); + +export const segmentNestedRules = buildSegmentModel({ + id: 5, + name: 'segment_nested_rules_all', + rules: [ + { + type: ALL_RULE, + rules: [ + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey1, + value: traitValue1 + }, + { + operator: EQUAL, + property_: traitKey2, + value: traitValue2 + } + ] + }, + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey_3, + value: traitValue3 + } + ] + } + ] + } + ] +}); + +export const segmentConditionsAndNestedRules = buildSegmentModel({ + id: 6, + name: 'segment_multiple_conditions_all_and_nested_rules', + rules: [ + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey1, + value: traitValue1 + } + ], + rules: [ + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey2, + value: traitValue2 + } + ] + }, + { + type: ALL_RULE, + conditions: [ + { + operator: EQUAL, + property_: traitKey_3, + value: traitValue3 + } + ] + } + ] + } + ] +}); diff --git a/tests/unit/utils.ts b/tests/unit/utils.ts new file mode 100644 index 0000000..91cca80 --- /dev/null +++ b/tests/unit/utils.ts @@ -0,0 +1,114 @@ +import { EnvironmentModel } from '../../flagsmith-engine/environments/models'; +import { CONSTANTS } from '../../flagsmith-engine/features/constants'; +import { FeatureModel, FeatureStateModel } from '../../flagsmith-engine/features/models'; +import { IdentityModel } from '../../flagsmith-engine/identities/models'; +import { TraitModel } from '../../flagsmith-engine/identities/traits/models'; +import { OrganisationModel } from '../../flagsmith-engine/organisations/models'; +import { ProjectModel } from '../../flagsmith-engine/projects/models'; +import { ALL_RULE, EQUAL } from '../../flagsmith-engine/segments/constants'; +import { + SegmentConditionModel, + SegmentModel, + SegmentRuleModel +} from '../../flagsmith-engine/segments/models'; + +export const segmentConditionProperty = 'foo'; +export const segmentConditionStringValue = 'bar'; + +export function segmentCondition() { + return new SegmentConditionModel(EQUAL, segmentConditionStringValue, segmentConditionProperty); +} + +export function traitMatchingSegment() { + return new TraitModel(segmentCondition().property_ as string, segmentCondition().value); +} + +export function organisation() { + return new OrganisationModel(1, 'test Org', true, false, true); +} + +export function segmentRule() { + const rule = new SegmentRuleModel(ALL_RULE); + rule.conditions = [segmentCondition()]; + return rule; +} + +export function segment() { + const segment = new SegmentModel(1, 'test name'); + segment.rules = [segmentRule()]; + return segment; +} + +export function project() { + const project = new ProjectModel(1, 'test project', false, organisation()); + project.segments = [segment()]; + return project; +} + +export function feature1() { + return new FeatureModel(1, 'feature_1', CONSTANTS.STANDARD); +} + +export function feature2() { + return new FeatureModel(2, 'feature_2', CONSTANTS.STANDARD); +} + +export function environment() { + const env = new EnvironmentModel(1, 'api-key', project()); + + env.featureStates = [ + new FeatureStateModel(feature1(), true, 1), + new FeatureStateModel(feature2(), false, 2) + ]; + + return env; +} + +export function identity() { + return new IdentityModel(Date.now().toString(), [], [], environment().apiKey, 'identity_1'); +} + +export function identityInSegment() { + const identity = new IdentityModel( + Date.now().toString(), + [], + [], + environment().apiKey, + 'identity_2' + ); + + identity.identityTraits = [traitMatchingSegment()]; + + return identity; +} + +export function getEnvironmentFeatureStateForFeatureByName( + environment: EnvironmentModel, + feature_name: string +): FeatureStateModel | undefined { + const features = environment.featureStates.filter(fs => fs.feature.name === feature_name); + return features.length > 0 ? features[0] : undefined; +} + +export function getEnvironmentFeatureStateForFeature( + environment: EnvironmentModel, + feature: FeatureModel +): FeatureStateModel | undefined { + const f = environment.featureStates.find(f => f.feature === feature); + return f; +} + +export function segmentOverrideFs() { + const fs = new FeatureStateModel(feature1(), false, 4); + fs.setValue('segment_override'); + return fs; +} + +export function environmentWithSegmentOverride(): EnvironmentModel { + const env = environment(); + const segm = segment(); + + segm.featureStates.push(segmentOverrideFs()); + env.project.segments.push(segm); + return env; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5e14dd1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "include": [ + "./flagsmith-engine" + ], + "compilerOptions": { + "outDir": "./build", + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "declaration": true, + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From 37e896488e5df112117149d042fdf7d48adb8421 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Tue, 8 Mar 2022 22:22:22 +0200 Subject: [PATCH 02/56] chore: refactor tests structure to account for sdk tests --- .gitmodules | 4 ++-- .../e2e}/engine.test.ts | 13 ++++++------- .../engine-tests/engine-test-data/.gitignore | 0 .../environment_n9fbf9h3v4fFgH3U3ngWhb.json | 0 .../engine-tests/engine-test-data/readme.md | 0 tests/{ => engine}/unit/egine.test.ts | 8 ++++---- .../unit/environments/builder.test.ts | 8 ++++---- .../unit/environments/models.test.ts | 2 +- .../{ => engine}/unit/features/models.test.ts | 4 ++-- .../identities/identities_builders.test.ts | 6 +++--- .../unit/identities/identities_models.test.ts | 8 ++++---- .../unit/organization/models.test.ts | 2 +- .../unit/segments/segments_model.test.ts | 4 ++-- tests/{ => engine}/unit/segments/util.ts | 6 +++--- tests/{ => engine}/unit/utils.ts | 18 +++++++++--------- 15 files changed, 41 insertions(+), 42 deletions(-) rename tests/{engine-tests => engine/e2e}/engine.test.ts (74%) rename tests/{ => engine}/engine-tests/engine-test-data/.gitignore (100%) rename tests/{ => engine}/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json (100%) rename tests/{ => engine}/engine-tests/engine-test-data/readme.md (100%) rename tests/{ => engine}/unit/egine.test.ts (91%) rename tests/{ => engine}/unit/environments/builder.test.ts (94%) rename tests/{ => engine}/unit/environments/models.test.ts (94%) rename tests/{ => engine}/unit/features/models.test.ts (94%) rename tests/{ => engine}/unit/identities/identities_builders.test.ts (91%) rename tests/{ => engine}/unit/identities/identities_models.test.ts (90%) rename tests/{ => engine}/unit/organization/models.test.ts (75%) rename tests/{ => engine}/unit/segments/segments_model.test.ts (97%) rename tests/{ => engine}/unit/segments/util.ts (93%) rename tests/{ => engine}/unit/utils.ts (80%) diff --git a/.gitmodules b/.gitmodules index 6ea4ff8..426ec2c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "tests/engine-tests/engine-test-data"] - path = tests/engine-tests/engine-test-data +[submodule "tests/engine/engine-tests/engine-test-data"] + path = tests/engine/engine-tests/engine-test-data url = git@github.com:Flagsmith/engine-test-data.git diff --git a/tests/engine-tests/engine.test.ts b/tests/engine/e2e/engine.test.ts similarity index 74% rename from tests/engine-tests/engine.test.ts rename to tests/engine/e2e/engine.test.ts index 834e416..188bb27 100644 --- a/tests/engine-tests/engine.test.ts +++ b/tests/engine/e2e/engine.test.ts @@ -1,10 +1,9 @@ import { readFileSync } from 'fs'; -import { getIdentityFeatureStates } from '../../flagsmith-engine'; -import { EnvironmentModel } from '../../flagsmith-engine/environments/models'; -import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util'; -import { IdentityModel } from '../../flagsmith-engine/identities/models'; -import { buildIdentityModel } from '../../flagsmith-engine/identities/util'; -import { identityInSegment } from '../unit/utils'; +import { getIdentityFeatureStates } from '../../../flagsmith-engine'; +import { EnvironmentModel } from '../../../flagsmith-engine/environments/models'; +import { buildEnvironmentModel } from '../../../flagsmith-engine/environments/util'; +import { IdentityModel } from '../../../flagsmith-engine/identities/models'; +import { buildIdentityModel } from '../../../flagsmith-engine/identities/util'; function extractTestCases( filePath: string @@ -29,7 +28,7 @@ function extractTestCases( test('Test Engine', () => { const testCases = extractTestCases( - __dirname + '/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json' + __dirname + '/../engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json' ); for (const testCase of testCases) { const engine_response = getIdentityFeatureStates(testCase.environment, testCase.identity); diff --git a/tests/engine-tests/engine-test-data/.gitignore b/tests/engine/engine-tests/engine-test-data/.gitignore similarity index 100% rename from tests/engine-tests/engine-test-data/.gitignore rename to tests/engine/engine-tests/engine-test-data/.gitignore diff --git a/tests/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json b/tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json similarity index 100% rename from tests/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json rename to tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json diff --git a/tests/engine-tests/engine-test-data/readme.md b/tests/engine/engine-tests/engine-test-data/readme.md similarity index 100% rename from tests/engine-tests/engine-test-data/readme.md rename to tests/engine/engine-tests/engine-test-data/readme.md diff --git a/tests/unit/egine.test.ts b/tests/engine/unit/egine.test.ts similarity index 91% rename from tests/unit/egine.test.ts rename to tests/engine/unit/egine.test.ts index 3f6614f..d41447c 100644 --- a/tests/unit/egine.test.ts +++ b/tests/engine/unit/egine.test.ts @@ -3,10 +3,10 @@ import { getEnvironmentFeatureStates, getIdentityFeatureState, getIdentityFeatureStates -} from '../../flagsmith-engine'; -import { CONSTANTS } from '../../flagsmith-engine/features/constants'; -import { FeatureModel, FeatureStateModel } from '../../flagsmith-engine/features/models'; -import { TraitModel } from '../../flagsmith-engine/identities/traits/models'; +} from '../../../flagsmith-engine'; +import { CONSTANTS } from '../../../flagsmith-engine/features/constants'; +import { FeatureModel, FeatureStateModel } from '../../../flagsmith-engine/features/models'; +import { TraitModel } from '../../../flagsmith-engine/identities/traits/models'; import { environment, environmentWithSegmentOverride, diff --git a/tests/unit/environments/builder.test.ts b/tests/engine/unit/environments/builder.test.ts similarity index 94% rename from tests/unit/environments/builder.test.ts rename to tests/engine/unit/environments/builder.test.ts index 1960be5..34c4683 100644 --- a/tests/unit/environments/builder.test.ts +++ b/tests/engine/unit/environments/builder.test.ts @@ -1,13 +1,13 @@ -import { EnvironmentModel } from '../../../flagsmith-engine/environments/models'; +import { EnvironmentModel } from '../../../../flagsmith-engine/environments/models'; import { buildEnvironmentAPIKeyModel, buildEnvironmentModel -} from '../../../flagsmith-engine/environments/util'; -import { CONSTANTS } from '../../../flagsmith-engine/features/constants'; +} from '../../../../flagsmith-engine/environments/util'; +import { CONSTANTS } from '../../../../flagsmith-engine/features/constants'; import { FeatureStateModel, MultivariateFeatureStateValueModel -} from '../../../flagsmith-engine/features/models'; +} from '../../../../flagsmith-engine/features/models'; import { getEnvironmentFeatureStateForFeatureByName } from '../utils'; test('test_get_flags_for_environment_returns_feature_states_for_environment_dictionary', () => { diff --git a/tests/unit/environments/models.test.ts b/tests/engine/unit/environments/models.test.ts similarity index 94% rename from tests/unit/environments/models.test.ts rename to tests/engine/unit/environments/models.test.ts index 20c27a6..e88739a 100644 --- a/tests/unit/environments/models.test.ts +++ b/tests/engine/unit/environments/models.test.ts @@ -1,4 +1,4 @@ -import { EnvironmentAPIKeyModel } from '../../../flagsmith-engine/environments/models'; +import { EnvironmentAPIKeyModel } from '../../../../flagsmith-engine/environments/models'; test('test_environment_api_key_model_is_valid_is_true_for_non_expired_active_key', () => { const environmentAPIKeyModel = new EnvironmentAPIKeyModel( diff --git a/tests/unit/features/models.test.ts b/tests/engine/unit/features/models.test.ts similarity index 94% rename from tests/unit/features/models.test.ts rename to tests/engine/unit/features/models.test.ts index 76e762d..2930269 100644 --- a/tests/unit/features/models.test.ts +++ b/tests/engine/unit/features/models.test.ts @@ -1,10 +1,10 @@ -import { CONSTANTS } from '../../../flagsmith-engine/features/constants'; +import { CONSTANTS } from '../../../../flagsmith-engine/features/constants'; import { FeatureModel, FeatureStateModel, MultivariateFeatureOptionModel, MultivariateFeatureStateValueModel -} from '../../../flagsmith-engine/features/models'; +} from '../../../../flagsmith-engine/features/models'; import { feature1 } from '../utils'; test('test_initializing_feature_state_creates_default_feature_state_uuid', () => { diff --git a/tests/unit/identities/identities_builders.test.ts b/tests/engine/unit/identities/identities_builders.test.ts similarity index 91% rename from tests/unit/identities/identities_builders.test.ts rename to tests/engine/unit/identities/identities_builders.test.ts index 3c15ce7..8badfc2 100644 --- a/tests/unit/identities/identities_builders.test.ts +++ b/tests/engine/unit/identities/identities_builders.test.ts @@ -1,6 +1,6 @@ -import { FeatureStateModel } from '../../../flagsmith-engine/features/models'; -import { IdentityModel } from '../../../flagsmith-engine/identities/models'; -import { buildIdentityModel } from '../../../flagsmith-engine/identities/util'; +import { FeatureStateModel } from '../../../../flagsmith-engine/features/models'; +import { IdentityModel } from '../../../../flagsmith-engine/identities/models'; +import { buildIdentityModel } from '../../../../flagsmith-engine/identities/util'; test('test_build_identity_model_from_dictionary_no_feature_states', () => { const identity = { diff --git a/tests/unit/identities/identities_models.test.ts b/tests/engine/unit/identities/identities_models.test.ts similarity index 90% rename from tests/unit/identities/identities_models.test.ts rename to tests/engine/unit/identities/identities_models.test.ts index 5aba3a8..dcea7c5 100644 --- a/tests/unit/identities/identities_models.test.ts +++ b/tests/engine/unit/identities/identities_models.test.ts @@ -1,7 +1,7 @@ -import { FeatureStateModel } from '../../../flagsmith-engine/features/models'; -import { IdentityModel } from '../../../flagsmith-engine/identities/models'; -import { TraitModel } from '../../../flagsmith-engine/identities/traits/models'; -import { buildIdentityModel } from '../../../flagsmith-engine/identities/util'; +import { FeatureStateModel } from '../../../../flagsmith-engine/features/models'; +import { IdentityModel } from '../../../../flagsmith-engine/identities/models'; +import { TraitModel } from '../../../../flagsmith-engine/identities/traits/models'; +import { buildIdentityModel } from '../../../../flagsmith-engine/identities/util'; import { feature1, identityInSegment } from '../utils'; test('test_composite_key', () => { diff --git a/tests/unit/organization/models.test.ts b/tests/engine/unit/organization/models.test.ts similarity index 75% rename from tests/unit/organization/models.test.ts rename to tests/engine/unit/organization/models.test.ts index 3b12f7b..1cb7ea4 100644 --- a/tests/unit/organization/models.test.ts +++ b/tests/engine/unit/organization/models.test.ts @@ -1,4 +1,4 @@ -import { buildOrganizationModel } from '../../../flagsmith-engine/organisations/util'; +import { buildOrganizationModel } from '../../../../flagsmith-engine/organisations/util'; test('Test builder', () => { const model = buildOrganizationModel({ diff --git a/tests/unit/segments/segments_model.test.ts b/tests/engine/unit/segments/segments_model.test.ts similarity index 97% rename from tests/unit/segments/segments_model.test.ts rename to tests/engine/unit/segments/segments_model.test.ts index 1811154..00c48a7 100644 --- a/tests/unit/segments/segments_model.test.ts +++ b/tests/engine/unit/segments/segments_model.test.ts @@ -3,13 +3,13 @@ import { ANY_RULE, CONDITION_OPERATORS, NONE_RULE -} from '../../../flagsmith-engine/segments/constants'; +} from '../../../../flagsmith-engine/segments/constants'; import { all, any, SegmentConditionModel, SegmentRuleModel -} from '../../../flagsmith-engine/segments/models'; +} from '../../../../flagsmith-engine/segments/models'; const conditionMatchCases: [string, string | number | boolean, string, boolean][] = [ [CONDITION_OPERATORS.EQUAL, 'bar', 'bar', true], diff --git a/tests/unit/segments/util.ts b/tests/engine/unit/segments/util.ts similarity index 93% rename from tests/unit/segments/util.ts rename to tests/engine/unit/segments/util.ts index 9b35241..bcb7cac 100644 --- a/tests/unit/segments/util.ts +++ b/tests/engine/unit/segments/util.ts @@ -1,6 +1,6 @@ -import { ALL_RULE, ANY_RULE, EQUAL } from '../../../flagsmith-engine/segments/constants'; -import { SegmentModel } from '../../../flagsmith-engine/segments/models'; -import { buildSegmentModel, buildSegmentRuleModel } from '../../../flagsmith-engine/segments/util'; +import { ALL_RULE, ANY_RULE, EQUAL } from '../../../../flagsmith-engine/segments/constants'; +import { SegmentModel } from '../../../../flagsmith-engine/segments/models'; +import { buildSegmentModel } from '../../../../flagsmith-engine/segments/util'; export const traitKey1 = 'email'; export const traitValue1 = 'user@example.com'; diff --git a/tests/unit/utils.ts b/tests/engine/unit/utils.ts similarity index 80% rename from tests/unit/utils.ts rename to tests/engine/unit/utils.ts index 91cca80..8a6af38 100644 --- a/tests/unit/utils.ts +++ b/tests/engine/unit/utils.ts @@ -1,16 +1,16 @@ -import { EnvironmentModel } from '../../flagsmith-engine/environments/models'; -import { CONSTANTS } from '../../flagsmith-engine/features/constants'; -import { FeatureModel, FeatureStateModel } from '../../flagsmith-engine/features/models'; -import { IdentityModel } from '../../flagsmith-engine/identities/models'; -import { TraitModel } from '../../flagsmith-engine/identities/traits/models'; -import { OrganisationModel } from '../../flagsmith-engine/organisations/models'; -import { ProjectModel } from '../../flagsmith-engine/projects/models'; -import { ALL_RULE, EQUAL } from '../../flagsmith-engine/segments/constants'; +import { EnvironmentModel } from '../../../flagsmith-engine/environments/models'; +import { CONSTANTS } from '../../../flagsmith-engine/features/constants'; +import { FeatureModel, FeatureStateModel } from '../../../flagsmith-engine/features/models'; +import { IdentityModel } from '../../../flagsmith-engine/identities/models'; +import { TraitModel } from '../../../flagsmith-engine/identities/traits/models'; +import { OrganisationModel } from '../../../flagsmith-engine/organisations/models'; +import { ProjectModel } from '../../../flagsmith-engine/projects/models'; +import { ALL_RULE, EQUAL } from '../../../flagsmith-engine/segments/constants'; import { SegmentConditionModel, SegmentModel, SegmentRuleModel -} from '../../flagsmith-engine/segments/models'; +} from '../../../flagsmith-engine/segments/models'; export const segmentConditionProperty = 'foo'; export const segmentConditionStringValue = 'bar'; From 35ceaa0b61ad48847f2dc89ccf4cebe94820c416 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 03:06:15 +0200 Subject: [PATCH 03/56] feat: add flagsmith node.js SDK implementation --- flagsmith-engine/identities/models.ts | 2 +- flagsmith-engine/index.ts | 2 +- package-lock.json | 21 ++ package.json | 1 + sdk/analytics.ts | 46 ++++ sdk/errors.ts | 2 + sdk/flagsmith.ts | 211 ++++++++++++++++++ sdk/index.ts | 0 sdk/models.ts | 143 ++++++++++++ sdk/polling_manager.ts | 29 +++ sdk/utils.ts | 10 + .../identities/identities_builders.test.ts | 8 +- tests/sdk/analytics.test.ts | 43 ++++ tests/sdk/data/environment.json | 33 +++ tests/sdk/data/flags.json | 20 ++ tests/sdk/data/identities.json | 29 +++ tests/sdk/flagsmith.test.ts | 184 +++++++++++++++ tests/sdk/polling.test.ts | 39 ++++ tests/sdk/utils.ts | 39 ++++ tsconfig.json | 3 +- 20 files changed, 858 insertions(+), 7 deletions(-) create mode 100644 sdk/analytics.ts create mode 100644 sdk/errors.ts create mode 100644 sdk/flagsmith.ts create mode 100644 sdk/index.ts create mode 100644 sdk/models.ts create mode 100644 sdk/polling_manager.ts create mode 100644 sdk/utils.ts create mode 100644 tests/sdk/analytics.test.ts create mode 100644 tests/sdk/data/environment.json create mode 100644 tests/sdk/data/flags.json create mode 100644 tests/sdk/data/identities.json create mode 100644 tests/sdk/flagsmith.test.ts create mode 100644 tests/sdk/polling.test.ts create mode 100644 tests/sdk/utils.ts diff --git a/flagsmith-engine/identities/models.ts b/flagsmith-engine/identities/models.ts index db340ce..d448061 100644 --- a/flagsmith-engine/identities/models.ts +++ b/flagsmith-engine/identities/models.ts @@ -7,7 +7,7 @@ const { v4: uuidv4 } = require('uuid'); export class IdentityModel { identifier: string; environmentApiKey: string; - createdDate; + createdDate?: number; identityFeatures: IdentityFeaturesList; identityTraits: TraitModel[]; identityUuid: string; diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index 92132fb..dbc93fd 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -32,7 +32,7 @@ function getIdentityFeatureStatesDict( } // Override with any feature states defined directly the identity - for (const fs of identity.identityFeatures) { + for (const fs of identity.identityFeatures || []) { if (feature_states[fs.feature.id]) { feature_states[fs.feature.id] = fs; } diff --git a/package-lock.json b/package-lock.json index 3c7dbd7..ad2b310 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "devDependencies": { "@types/jest": "^27.4.1", "@types/md5": "^2.3.2", + "@types/node-fetch": "^2.6.1", "@types/uuid": "^8.3.4", "esbuild": "^0.14.25", "husky": "^7.0.4", @@ -1002,6 +1003,16 @@ "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", "dev": true }, + "node_modules/@types/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, "node_modules/@types/prettier": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", @@ -5340,6 +5351,16 @@ "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", "dev": true }, + "@types/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, "@types/prettier": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", diff --git a/package.json b/package.json index bf0aa4e..c622af0 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "devDependencies": { "@types/jest": "^27.4.1", "@types/md5": "^2.3.2", + "@types/node-fetch": "^2.6.1", "@types/uuid": "^8.3.4", "esbuild": "^0.14.25", "husky": "^7.0.4", diff --git a/sdk/analytics.ts b/sdk/analytics.ts new file mode 100644 index 0000000..4bda70c --- /dev/null +++ b/sdk/analytics.ts @@ -0,0 +1,46 @@ +import fetch from 'node-fetch'; + +const ANALYTICS_ENDPOINT = 'analytics/flags/'; +const ANALYTICS_TIMER = 10; + +export class AnalyticsProcessor { + private analytics_endpoint: string; + private environment_key: string; + private _last_flushed: number; + analytics_data: { [key: string]: any }; + private timeout: number = 3; + + constructor(data: { environment_key: string; base_api_url: string; timeout?: number }) { + this.analytics_endpoint = data.base_api_url + ANALYTICS_ENDPOINT; + this.environment_key = data.environment_key; + this._last_flushed = Date.now(); + this.analytics_data = {}; + this.timeout = data.timeout || this.timeout; + } + + async flush() { + if (!Object.keys(this.analytics_data).length) { + return; + } + + await fetch(this.analytics_endpoint, { + method: 'POST', + body: JSON.stringify(this.analytics_data), + timeout: this.timeout, + headers: { + 'Content-Type': 'application/json', + 'X-Environment-Key': this.environment_key + } + }); + + this.analytics_data = {}; + this._last_flushed = Date.now(); + } + + trackFeature(featureId: number) { + this.analytics_data[featureId] = (this.analytics_data[featureId] || 0) + 1; + if (Date.now() - this._last_flushed > ANALYTICS_TIMER * 1000) { + this.flush(); + } + } +} diff --git a/sdk/errors.ts b/sdk/errors.ts new file mode 100644 index 0000000..199c3c0 --- /dev/null +++ b/sdk/errors.ts @@ -0,0 +1,2 @@ +export class FlagsmithClientError extends Error {} +export class FlagsmithAPIError extends Error {} diff --git a/sdk/flagsmith.ts b/sdk/flagsmith.ts new file mode 100644 index 0000000..146e2d7 --- /dev/null +++ b/sdk/flagsmith.ts @@ -0,0 +1,211 @@ +import fetch from 'node-fetch'; +import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine'; +import { EnvironmentModel } from '../flagsmith-engine/environments/models'; +import { buildEnvironmentModel } from '../flagsmith-engine/environments/util'; +import { IdentityModel } from '../flagsmith-engine/identities/models'; +import { TraitModel } from '../flagsmith-engine/identities/traits/models'; + +import { AnalyticsProcessor } from './analytics'; +import { FlagsmithAPIError, FlagsmithClientError } from './errors'; + +import { DefaultFlag, Flags } from './models'; +import { EnvironmentDataPollingManager } from './polling_manager'; +import { generate_identities_data } from './utils'; + +const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; + +export class Flagsmith { + environment_key?: string; + api_url: string = DEFAULT_API_URL; + custom_headers?: { [key: string]: any }; + request_timeout_seconds?: number; + enable_local_evaluation?: boolean = false; + environment_refresh_interval_seconds: number = 60; + retries?: any; + enable_analytics: boolean = false; + default_flag_handler?: (featureName: string) => DefaultFlag; + + environment_flags_url: string; + identities_url: string; + environment_url: string; + + environment_data_polling_manager_thread?: EnvironmentDataPollingManager; + environment?: EnvironmentModel; + private _analytics_processor?: AnalyticsProcessor; + + constructor(data: { + environment_key: string; + api_url?: string; + custom_headers?: { [key: string]: any }; + request_timeout_seconds?: number; + enable_local_evaluation?: boolean; + environment_refresh_interval_seconds?: number; + retries?: any; + enable_analytics?: boolean; + default_flag_handler?: (featureName: string) => DefaultFlag; + }) { + this.environment_key = data.environment_key; + this.api_url = data.api_url || this.api_url; + this.custom_headers = data.custom_headers; + this.request_timeout_seconds = data.request_timeout_seconds; + this.enable_local_evaluation = data.enable_local_evaluation; + this.environment_refresh_interval_seconds = + data.environment_refresh_interval_seconds || this.environment_refresh_interval_seconds; + this.retries = data.retries; + this.enable_analytics = data.enable_analytics || false; + this.default_flag_handler = data.default_flag_handler; + + this.environment_flags_url = `${this.api_url}flags/`; + this.identities_url = `${this.api_url}identities/`; + this.environment_url = `${this.api_url}environment-document/`; + + this.environment; + if (this.enable_local_evaluation) { + this.environment_data_polling_manager_thread = new EnvironmentDataPollingManager( + this, + this.environment_refresh_interval_seconds + ); + this.environment_data_polling_manager_thread.start(); + } + + this._analytics_processor = data.enable_analytics + ? new AnalyticsProcessor({ + environment_key: this.environment_key, + base_api_url: this.api_url, + timeout: this.request_timeout_seconds + }) + : undefined; + } + + async getEnvironmentFlags(): Promise { + if (this.environment) { + return new Promise(resolve => resolve(this._get_environment_flags_from_document())); + } + + return this._get_environment_flags_from_api(); + } + + getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { + traits = traits || {}; + if (this.environment) { + return new Promise(resolve => + resolve(this._get_identity_flags_from_document(identifier, traits || {})) + ); + } + return this._get_identity_flags_from_api(identifier, traits); + } + + async update_environment() { + this.environment = await this._get_environment_from_api(); + } + + private async _get_json_response( + url: string, + method: string, + body?: { [key: string]: any } + ): Promise { + const data = await fetch(url, { + method: method, + timeout: this.request_timeout_seconds || undefined, + body: JSON.stringify(body) + }); + + if (data.status !== 200) { + throw new FlagsmithAPIError( + `Invalid request made to Flagsmith API. Response status code: ${data.status}` + ); + } + + return data.json(); + } + + private async _get_environment_from_api() { + const environment_data = await this._get_json_response(this.environment_url, 'GET'); + return buildEnvironmentModel(environment_data); + } + + private _get_environment_flags_from_document() { + if (!this.environment) { + throw new FlagsmithClientError( + 'Unable to build identity model when no local environment present.' + ); + } + + return Flags.fromFeatureStateModels({ + featureStates: getEnvironmentFeatureStates(this.environment), + analyticsProcessor: this._analytics_processor, + defaultFlagHandler: this.default_flag_handler + }); + } + + private _get_identity_flags_from_document(identifier: string, traits: { [key: string]: any }) { + if (!this.environment) { + throw new FlagsmithClientError( + 'Unable to build identity model when no local environment present.' + ); + } + + const identityModel = this._build_identity_model(identifier, Object.values(traits)); + const featureStates = getIdentityFeatureStates(this.environment, identityModel); + + return Flags.fromFeatureStateModels({ + featureStates: featureStates, + analyticsProcessor: this._analytics_processor, + defaultFlagHandler: this.default_flag_handler + }); + } + + private async _get_environment_flags_from_api() { + try { + const apiFlags = await this._get_json_response(this.environment_flags_url, 'GET'); + return Flags.fromAPIFlags({ + apiFlags: apiFlags, + analyticsProcessor: this._analytics_processor, + defaultFlagHandler: this.default_flag_handler + }); + } catch (e) { + if (this.default_flag_handler) { + return new Flags({ + flags: {}, + defaultFlagHandler: this.default_flag_handler + }); + } + + throw e; + } + } + + private async _get_identity_flags_from_api(identifier: string, traits: { [key: string]: any }) { + try { + const data = generate_identities_data(identifier, traits); + const jsonResponse = await this._get_json_response(this.identities_url, 'POST', data); + return Flags.fromAPIFlags({ + apiFlags: jsonResponse['flags'], + analyticsProcessor: this._analytics_processor, + defaultFlagHandler: this.default_flag_handler + }); + } catch (e) { + if (this.default_flag_handler) { + return new Flags({ + flags: {}, + defaultFlagHandler: this.default_flag_handler + }); + } + + throw e; + } + } + + private _build_identity_model(identifier: string, traits: any[]) { + if (!this.environment) { + throw new FlagsmithClientError( + 'Unable to build identity model when no local environment present.' + ); + } + + const traitModels = traits.map(trait => new TraitModel(trait.key, trait.value)); + return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); + } + + stop() {} +} diff --git a/sdk/index.ts b/sdk/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/sdk/models.ts b/sdk/models.ts new file mode 100644 index 0000000..51ab470 --- /dev/null +++ b/sdk/models.ts @@ -0,0 +1,143 @@ +import { FeatureStateModel } from '../flagsmith-engine/features/models'; +import { AnalyticsProcessor } from './analytics'; +import { FlagsmithClientError } from './errors'; + +export class BaseFlag { + enabled: boolean; + value: string | number | boolean | undefined; + isDefault: boolean; + + constructor( + value: string | number | boolean | undefined, + enabled: boolean, + isDefault: boolean + ) { + this.value = value; + this.enabled = enabled; + this.isDefault = isDefault; + } +} + +export class DefaultFlag extends BaseFlag { + constructor(value: string | number | boolean | undefined, enabled: boolean) { + super(value, enabled, true); + } +} + +export class Flag extends BaseFlag { + featureId: number; + featureName: string; + + constructor(params: { + value: string | number | boolean | undefined; + enabled: boolean; + isDefault?: boolean; + featureId: number; + featureName: string; + }) { + super(params.value, params.enabled, !!params.isDefault); + this.featureId = params.featureId; + this.featureName = params.featureName; + } + + static fromFeatureStateModel( + fsm: FeatureStateModel, + identityId: number | string | undefined + ): Flag { + return new Flag({ + value: fsm.getValue(identityId), + enabled: fsm.enabled, + featureId: fsm.feature.id, + featureName: fsm.feature.name + }); + } + + static fromAPIFlag(flagData: any): Flag { + return new Flag({ + enabled: flagData['enabled'], + value: flagData['feature_state_value'] || flagData['value'], + featureId: flagData['feature']['id'], + featureName: flagData['feature']['name'] + }); + } +} + +export class Flags { + flags: { [key: string]: Flag } = {}; + defaultFlagHandler?: (featureName: string) => DefaultFlag; + analyticsProcessor?: AnalyticsProcessor; + + constructor(data: { + flags: { [key: string]: Flag }; + defaultFlagHandler?: (v: string) => DefaultFlag; + analyticsProcessor?: AnalyticsProcessor; + }) { + this.flags = data.flags; + this.defaultFlagHandler = data.defaultFlagHandler; + this.analyticsProcessor = data.analyticsProcessor; + } + + static fromFeatureStateModels(data: { + featureStates: FeatureStateModel[]; + analyticsProcessor?: AnalyticsProcessor; + defaultFlagHandler?: (f: string) => DefaultFlag; + identityID?: string | number; + }): Flags { + const flags: { [key: string]: any } = {}; + for (const fs of data.featureStates) { + flags[fs.feature.name] = Flag.fromFeatureStateModel(fs, data.identityID); + } + return new Flags({ + flags: flags, + defaultFlagHandler: data.defaultFlagHandler, + analyticsProcessor: data.analyticsProcessor + }); + } + + static fromAPIFlags(data: { + apiFlags: { [key: string]: any }[]; + analyticsProcessor?: AnalyticsProcessor; + defaultFlagHandler?: (v: string) => DefaultFlag; + }): Flags { + const flags: { [key: string]: any } = {}; + + for (const flagData of data.apiFlags) { + flags[flagData['feature']['name']] = Flag.fromAPIFlag(flagData); + } + + return new Flags({ + flags: flags, + defaultFlagHandler: data.defaultFlagHandler, + analyticsProcessor: data.analyticsProcessor + }); + } + + allFlags(): Flag[] { + return Object.values(this.flags); + } + + getFlag(featureName: string): BaseFlag { + const flag = this.flags[featureName]; + + if (!flag) { + if (this.defaultFlagHandler) { + return this.defaultFlagHandler(featureName); + } + throw new FlagsmithClientError(`Feature does not exist: ${featureName}`); + } + + if (this.analyticsProcessor && flag.featureId) { + this.analyticsProcessor.trackFeature(flag.featureId); + } + + return flag; + } + + getFeatureValue(featureName: string): any { + return this.getFlag(featureName).value; + } + + isFeatureEnabled(featureName: string): boolean { + return this.getFlag(featureName).enabled; + } +} diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts new file mode 100644 index 0000000..37eee65 --- /dev/null +++ b/sdk/polling_manager.ts @@ -0,0 +1,29 @@ +import { Flagsmith } from './flagsmith'; + +export class EnvironmentDataPollingManager { + private interval?: NodeJS.Timer; + private main: Flagsmith; + private refreshIntervalSeconds: number; + + constructor(main: Flagsmith, refreshIntervalSeconds: number) { + this.main = main; + this.refreshIntervalSeconds = refreshIntervalSeconds; + } + + start() { + const updateEnvironemnt = () => { + this.interval = setInterval(async () => { + await this.main.update_environment(); + }, this.refreshIntervalSeconds * 1000); + }; + + this.interval = setTimeout(updateEnvironemnt, this.refreshIntervalSeconds * 1000); + } + + stop() { + if (!this.interval) { + return; + } + clearInterval(this.interval); + } +} diff --git a/sdk/utils.ts b/sdk/utils.ts new file mode 100644 index 0000000..ef24f75 --- /dev/null +++ b/sdk/utils.ts @@ -0,0 +1,10 @@ +export function generate_identities_data(identifier: string, traits?: { [key: string]: any }) { + const traitsGenerated = Object.values(traits || {}).map(trait => ({ + trait_key: trait[0], + trait_value: trait[1] + })); + return { + identifier: identifier, + traits: traitsGenerated + }; +} diff --git a/tests/engine/unit/identities/identities_builders.test.ts b/tests/engine/unit/identities/identities_builders.test.ts index 8badfc2..663f286 100644 --- a/tests/engine/unit/identities/identities_builders.test.ts +++ b/tests/engine/unit/identities/identities_builders.test.ts @@ -13,7 +13,7 @@ test('test_build_identity_model_from_dictionary_no_feature_states', () => { const identityModel = buildIdentityModel(identity); - expect(identityModel.identityFeatures.length).toBe(0); + expect(identityModel.identityFeatures?.length).toBe(0); expect(identityModel.identityTraits.length).toBe(1); }); @@ -39,7 +39,7 @@ test('test_build_identity_model_from_dictionary_uses_identity_feature_list_for_i const identityModel = buildIdentityModel(identity_dict); - expect(identityModel.identityFeatures.length).toBe(1); + expect(identityModel.identityFeatures?.length).toBe(1); }); test('test_build_build_identity_model_from_dict_creates_identity_uuid', () => { @@ -73,8 +73,8 @@ test('test_build_identity_model_from_dictionary_with_feature_states', () => { const identityModel = buildIdentityModel(identity_dict); expect(identityModel).toBeInstanceOf(IdentityModel); - expect(identityModel.identityFeatures.length).toBe(1); - expect(identityModel.identityFeatures[0]).toBeInstanceOf(FeatureStateModel); + expect(identityModel.identityFeatures?.length).toBe(1); + expect(identityModel?.identityFeatures![0]).toBeInstanceOf(FeatureStateModel); }); test('test_identity_dict_created_using_model_can_convert_back_to_model', () => { diff --git a/tests/sdk/analytics.test.ts b/tests/sdk/analytics.test.ts new file mode 100644 index 0000000..82d3969 --- /dev/null +++ b/tests/sdk/analytics.test.ts @@ -0,0 +1,43 @@ +jest.mock('node-fetch'); +import fetch from 'node-fetch'; +import { analyticsProcessor } from './utils'; + +afterEach(() => { + jest.clearAllMocks(); +}); + +test('test_analytics_processor_track_feature_updates_analytics_data', () => { + const aP = analyticsProcessor(); + aP.trackFeature(1); + expect(aP.analytics_data[1]).toBe(1); + + aP.trackFeature(1); + expect(aP.analytics_data[1]).toBe(2); +}); + +test('test_analytics_processor_flush_clears_analytics_data', async () => { + const aP = analyticsProcessor(); + aP.trackFeature(1); + await aP.flush(); + expect(aP.analytics_data).toStrictEqual({}); +}); + +test('test_analytics_processor_flush_post_request_data_match_ananlytics_data', async () => { + const aP = analyticsProcessor(); + aP.trackFeature(1); + aP.trackFeature(2); + await aP.flush(); + expect(fetch).toHaveBeenCalledTimes(1); + expect(fetch).toHaveBeenCalledWith('http://testUrlanalytics/flags/', { + body: '{"1":1,"2":1}', + headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'test-key' }, + method: 'POST', + timeout: 3 + }); +}); + +test('test_analytics_processor_flush_early_exit_if_analytics_data_is_empty', async () => { + const aP = analyticsProcessor(); + await aP.flush(); + expect(fetch).not.toHaveBeenCalled(); +}); diff --git a/tests/sdk/data/environment.json b/tests/sdk/data/environment.json new file mode 100644 index 0000000..d872ff1 --- /dev/null +++ b/tests/sdk/data/environment.json @@ -0,0 +1,33 @@ +{ + "api_key": "B62qaMZNwfiqT76p38ggrQ", + "project": { + "name": "Test project", + "organisation": { + "feature_analytics": false, + "name": "Test Org", + "id": 1, + "persist_trait_data": true, + "stop_serving_flags": false + }, + "id": 1, + "hide_disabled_flags": false, + "segments": [] + }, + "segment_overrides": [], + "id": 1, + "feature_states": [ + { + "multivariate_feature_state_values": [], + "feature_state_value": "some-value", + "id": 1, + "featurestate_uuid": "40eb539d-3713-4720-bbd4-829dbef10d51", + "feature": { + "name": "some_feature", + "type": "STANDARD", + "id": 1 + }, + "segment_id": null, + "enabled": true + } + ] +} \ No newline at end of file diff --git a/tests/sdk/data/flags.json b/tests/sdk/data/flags.json new file mode 100644 index 0000000..cf06066 --- /dev/null +++ b/tests/sdk/data/flags.json @@ -0,0 +1,20 @@ +[ + { + "id": 1, + "feature": { + "id": 1, + "name": "some_feature", + "created_date": "2019-08-27T14:53:45.698555Z", + "initial_value": null, + "description": null, + "default_enabled": false, + "type": "STANDARD", + "project": 1 + }, + "feature_state_value": "some-value", + "enabled": true, + "environment": 1, + "identity": null, + "feature_segment": null + } +] \ No newline at end of file diff --git a/tests/sdk/data/identities.json b/tests/sdk/data/identities.json new file mode 100644 index 0000000..1d9c679 --- /dev/null +++ b/tests/sdk/data/identities.json @@ -0,0 +1,29 @@ +{ + "traits": [ + { + "id": 1, + "trait_key": "some_trait", + "trait_value": "some_value" + } + ], + "flags": [ + { + "id": 1, + "feature": { + "id": 1, + "name": "some_feature", + "created_date": "2019-08-27T14:53:45.698555Z", + "initial_value": null, + "description": null, + "default_enabled": false, + "type": "STANDARD", + "project": 1 + }, + "feature_state_value": "some-value", + "enabled": true, + "environment": 1, + "identity": null, + "feature_segment": null + } + ] +} \ No newline at end of file diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts new file mode 100644 index 0000000..0a4ea19 --- /dev/null +++ b/tests/sdk/flagsmith.test.ts @@ -0,0 +1,184 @@ +import { Flagsmith } from '../../sdk/flagsmith'; +import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; +import fetch, { Headers } from 'node-fetch'; +import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils'; +import { DefaultFlag } from '../../sdk/models'; + +jest.mock('node-fetch'); +jest.mock('../../sdk/polling_manager'); +const { Response } = jest.requireActual('node-fetch'); + +beforeEach(() => { + // @ts-ignore + jest.clearAllMocks(); +}); + +test('test_flagsmith_starts_polling_manager_on_init_if_enabled', () => { + new Flagsmith({ + environment_key: 'key', + enable_local_evaluation: true + }); + expect(EnvironmentDataPollingManager).toBeCalled(); +}); + +test('test_update_environment_sets_environment', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + const flg = flagsmith(); + await flg.update_environment(); + expect(flg.environment).toBeDefined(); + + // @ts-ignore + flg.environment.featureStates[0].featurestateUUID = undefined; + // @ts-ignore + const model = environmentModel(JSON.parse(environmentJSON())); + // @ts-ignore + model.featureStates[0].featurestateUUID = undefined; + expect(flg.environment).toStrictEqual(model); +}); +test('test_get_environment_flags_calls_api_when_no_local_environment', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const flg = flagsmith(); + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + + expect(fetch).toBeCalledTimes(1); + expect(allFlags[0].enabled).toBe(true); + expect(allFlags[0].value).toBe('some-value'); + expect(allFlags[0].featureName).toBe('some_feature'); +}); +test('test_get_environment_flags_uses_local_environment_when_available', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const flg = flagsmith(); + const model = environmentModel(JSON.parse(environmentJSON())); + flg.environment = model; + + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + expect(fetch).toBeCalledTimes(0); + expect(allFlags[0].enabled).toBe(model.featureStates[0].enabled); + expect(allFlags[0].value).toBe(model.featureStates[0].getValue()); + expect(allFlags[0].featureName).toBe(model.featureStates[0].feature.name); +}); +test('test_get_identity_flags_calls_api_when_no_local_environment_no_traits', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + const identifier = 'identifier'; + + const flg = flagsmith(); + + const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags(); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); +test('test_get_identity_flags_calls_api_when_no_local_environment_with_traits', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + const identifier = 'identifier'; + const traits = { some_trait: 'some_value' }; + const flg = flagsmith(); + + const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags(); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + +test('test_default_flag_is_used_when_no_environment_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify([])))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environment_key: 'key', + default_flag_handler: defaultFlagHandler + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + expect(flag.isDefault).toBe(true); + expect(flag.enabled).toBe(defaultFlag.enabled); + expect(flag.value).toBe(defaultFlag.value); +}); + +test('test_non_200_response_raises_flagsmith_api_error', async () => { + const errorResponse403 = new Response('403 Forbidden', { + status: 403 + }); + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(errorResponse403)); + + const flg = new Flagsmith({ + environment_key: 'some' + }); + + await expect(flg.getEnvironmentFlags()).rejects.toThrow(); +}); +test('test_default_flag_is_not_used_when_environment_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environment_key: 'key', + default_flag_handler: defaultFlagHandler + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.value).not.toBe(defaultFlag.value); + expect(flag.value).toBe('some-value'); +}); +test('test_default_flag_is_not_used_when_identity_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environment_key: 'key', + default_flag_handler: defaultFlagHandler + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.value).not.toBe(defaultFlag.value); + expect(flag.value).toBe('some-value'); +}); + +test('test_default_flag_is_used_when_no_identity_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environment_key: 'key', + default_flag_handler: defaultFlagHandler + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(defaultFlag.value); + expect(flag.enabled).toBe(defaultFlag.enabled); +}); diff --git a/tests/sdk/polling.test.ts b/tests/sdk/polling.test.ts new file mode 100644 index 0000000..0a58e85 --- /dev/null +++ b/tests/sdk/polling.test.ts @@ -0,0 +1,39 @@ +import { Flagsmith } from '../../sdk/flagsmith'; +import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; +jest.mock('../../sdk/flagsmith'); +jest.mock('node-fetch'); + +beforeEach(() => { + // @ts-ignore + Flagsmith.mockClear(); +}); + +function sleep(ms: number) { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +test('test_polling_manager_calls_update_environment_on_start', async () => { + const flagsmith = new Flagsmith({ + environment_key: 'key' + }); + + const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); + pollingManager.start(); + await sleep(500); + pollingManager.stop(); + expect(flagsmith.update_environment).toHaveBeenCalled(); +}); + +test('test_polling_manager_calls_update_environment_on_each_refresh', async () => { + const flagsmith = new Flagsmith({ + environment_key: 'key' + }); + + const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); + pollingManager.start(); + await sleep(450); + pollingManager.stop(); + expect(flagsmith.update_environment).toHaveBeenCalledTimes(3); +}); diff --git a/tests/sdk/utils.ts b/tests/sdk/utils.ts new file mode 100644 index 0000000..887cec4 --- /dev/null +++ b/tests/sdk/utils.ts @@ -0,0 +1,39 @@ +import { readFileSync } from 'fs'; +import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util'; +import { AnalyticsProcessor } from '../../sdk/analytics'; +import { Flagsmith } from '../../sdk/flagsmith'; + +const DATA_DIR = __dirname + '/data/'; + +export function analyticsProcessor() { + return new AnalyticsProcessor({ + environment_key: 'test-key', + base_api_url: 'http://testUrl' + }); +} + +export function apiKey(): string { + return 'sometestfakekey'; +} + +export function flagsmith() { + return new Flagsmith({ + environment_key: apiKey() + }); +} + +export function environmentJSON() { + return readFileSync(DATA_DIR + 'environment.json', 'utf-8'); +} + +export function environmentModel(environmentJSON: any) { + return buildEnvironmentModel(environmentJSON); +} + +export function flagsJSON() { + return readFileSync(DATA_DIR + 'flags.json', 'utf-8'); +} + +export function identitiesJSON() { + return readFileSync(DATA_DIR + 'identities.json', 'utf-8'); +} diff --git a/tsconfig.json b/tsconfig.json index 5e14dd1..9195571 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "include": [ - "./flagsmith-engine" + "./flagsmith-engine", + "./sdk" ], "compilerOptions": { "outDir": "./build", From d8bfea912ca0c715f9ae1f877fca298df1973ae4 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 03:47:29 +0200 Subject: [PATCH 04/56] chore: minor refactoring --- sdk/analytics.ts | 34 +++--- sdk/flagsmith.ts | 211 --------------------------------- sdk/index.ts | 225 ++++++++++++++++++++++++++++++++++++ sdk/polling_manager.ts | 2 +- sdk/utils.ts | 2 +- tests/sdk/analytics.test.ts | 6 +- tests/sdk/flagsmith.test.ts | 24 ++-- tests/sdk/polling.test.ts | 8 +- tests/sdk/utils.ts | 8 +- 9 files changed, 267 insertions(+), 253 deletions(-) delete mode 100644 sdk/flagsmith.ts diff --git a/sdk/analytics.ts b/sdk/analytics.ts index 4bda70c..8cf1d75 100644 --- a/sdk/analytics.ts +++ b/sdk/analytics.ts @@ -4,42 +4,42 @@ const ANALYTICS_ENDPOINT = 'analytics/flags/'; const ANALYTICS_TIMER = 10; export class AnalyticsProcessor { - private analytics_endpoint: string; - private environment_key: string; - private _last_flushed: number; - analytics_data: { [key: string]: any }; + private analyticsEndpoint: string; + private environmentKey: string; + private lastFlushed: number; + analyticsData: { [key: string]: any }; private timeout: number = 3; - constructor(data: { environment_key: string; base_api_url: string; timeout?: number }) { - this.analytics_endpoint = data.base_api_url + ANALYTICS_ENDPOINT; - this.environment_key = data.environment_key; - this._last_flushed = Date.now(); - this.analytics_data = {}; + constructor(data: { environmentKey: string; baseApiUrl: string; timeout?: number }) { + this.analyticsEndpoint = data.baseApiUrl + ANALYTICS_ENDPOINT; + this.environmentKey = data.environmentKey; + this.lastFlushed = Date.now(); + this.analyticsData = {}; this.timeout = data.timeout || this.timeout; } async flush() { - if (!Object.keys(this.analytics_data).length) { + if (!Object.keys(this.analyticsData).length) { return; } - await fetch(this.analytics_endpoint, { + await fetch(this.analyticsEndpoint, { method: 'POST', - body: JSON.stringify(this.analytics_data), + body: JSON.stringify(this.analyticsData), timeout: this.timeout, headers: { 'Content-Type': 'application/json', - 'X-Environment-Key': this.environment_key + 'X-Environment-Key': this.environmentKey } }); - this.analytics_data = {}; - this._last_flushed = Date.now(); + this.analyticsData = {}; + this.lastFlushed = Date.now(); } trackFeature(featureId: number) { - this.analytics_data[featureId] = (this.analytics_data[featureId] || 0) + 1; - if (Date.now() - this._last_flushed > ANALYTICS_TIMER * 1000) { + this.analyticsData[featureId] = (this.analyticsData[featureId] || 0) + 1; + if (Date.now() - this.lastFlushed > ANALYTICS_TIMER * 1000) { this.flush(); } } diff --git a/sdk/flagsmith.ts b/sdk/flagsmith.ts deleted file mode 100644 index 146e2d7..0000000 --- a/sdk/flagsmith.ts +++ /dev/null @@ -1,211 +0,0 @@ -import fetch from 'node-fetch'; -import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine'; -import { EnvironmentModel } from '../flagsmith-engine/environments/models'; -import { buildEnvironmentModel } from '../flagsmith-engine/environments/util'; -import { IdentityModel } from '../flagsmith-engine/identities/models'; -import { TraitModel } from '../flagsmith-engine/identities/traits/models'; - -import { AnalyticsProcessor } from './analytics'; -import { FlagsmithAPIError, FlagsmithClientError } from './errors'; - -import { DefaultFlag, Flags } from './models'; -import { EnvironmentDataPollingManager } from './polling_manager'; -import { generate_identities_data } from './utils'; - -const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; - -export class Flagsmith { - environment_key?: string; - api_url: string = DEFAULT_API_URL; - custom_headers?: { [key: string]: any }; - request_timeout_seconds?: number; - enable_local_evaluation?: boolean = false; - environment_refresh_interval_seconds: number = 60; - retries?: any; - enable_analytics: boolean = false; - default_flag_handler?: (featureName: string) => DefaultFlag; - - environment_flags_url: string; - identities_url: string; - environment_url: string; - - environment_data_polling_manager_thread?: EnvironmentDataPollingManager; - environment?: EnvironmentModel; - private _analytics_processor?: AnalyticsProcessor; - - constructor(data: { - environment_key: string; - api_url?: string; - custom_headers?: { [key: string]: any }; - request_timeout_seconds?: number; - enable_local_evaluation?: boolean; - environment_refresh_interval_seconds?: number; - retries?: any; - enable_analytics?: boolean; - default_flag_handler?: (featureName: string) => DefaultFlag; - }) { - this.environment_key = data.environment_key; - this.api_url = data.api_url || this.api_url; - this.custom_headers = data.custom_headers; - this.request_timeout_seconds = data.request_timeout_seconds; - this.enable_local_evaluation = data.enable_local_evaluation; - this.environment_refresh_interval_seconds = - data.environment_refresh_interval_seconds || this.environment_refresh_interval_seconds; - this.retries = data.retries; - this.enable_analytics = data.enable_analytics || false; - this.default_flag_handler = data.default_flag_handler; - - this.environment_flags_url = `${this.api_url}flags/`; - this.identities_url = `${this.api_url}identities/`; - this.environment_url = `${this.api_url}environment-document/`; - - this.environment; - if (this.enable_local_evaluation) { - this.environment_data_polling_manager_thread = new EnvironmentDataPollingManager( - this, - this.environment_refresh_interval_seconds - ); - this.environment_data_polling_manager_thread.start(); - } - - this._analytics_processor = data.enable_analytics - ? new AnalyticsProcessor({ - environment_key: this.environment_key, - base_api_url: this.api_url, - timeout: this.request_timeout_seconds - }) - : undefined; - } - - async getEnvironmentFlags(): Promise { - if (this.environment) { - return new Promise(resolve => resolve(this._get_environment_flags_from_document())); - } - - return this._get_environment_flags_from_api(); - } - - getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { - traits = traits || {}; - if (this.environment) { - return new Promise(resolve => - resolve(this._get_identity_flags_from_document(identifier, traits || {})) - ); - } - return this._get_identity_flags_from_api(identifier, traits); - } - - async update_environment() { - this.environment = await this._get_environment_from_api(); - } - - private async _get_json_response( - url: string, - method: string, - body?: { [key: string]: any } - ): Promise { - const data = await fetch(url, { - method: method, - timeout: this.request_timeout_seconds || undefined, - body: JSON.stringify(body) - }); - - if (data.status !== 200) { - throw new FlagsmithAPIError( - `Invalid request made to Flagsmith API. Response status code: ${data.status}` - ); - } - - return data.json(); - } - - private async _get_environment_from_api() { - const environment_data = await this._get_json_response(this.environment_url, 'GET'); - return buildEnvironmentModel(environment_data); - } - - private _get_environment_flags_from_document() { - if (!this.environment) { - throw new FlagsmithClientError( - 'Unable to build identity model when no local environment present.' - ); - } - - return Flags.fromFeatureStateModels({ - featureStates: getEnvironmentFeatureStates(this.environment), - analyticsProcessor: this._analytics_processor, - defaultFlagHandler: this.default_flag_handler - }); - } - - private _get_identity_flags_from_document(identifier: string, traits: { [key: string]: any }) { - if (!this.environment) { - throw new FlagsmithClientError( - 'Unable to build identity model when no local environment present.' - ); - } - - const identityModel = this._build_identity_model(identifier, Object.values(traits)); - const featureStates = getIdentityFeatureStates(this.environment, identityModel); - - return Flags.fromFeatureStateModels({ - featureStates: featureStates, - analyticsProcessor: this._analytics_processor, - defaultFlagHandler: this.default_flag_handler - }); - } - - private async _get_environment_flags_from_api() { - try { - const apiFlags = await this._get_json_response(this.environment_flags_url, 'GET'); - return Flags.fromAPIFlags({ - apiFlags: apiFlags, - analyticsProcessor: this._analytics_processor, - defaultFlagHandler: this.default_flag_handler - }); - } catch (e) { - if (this.default_flag_handler) { - return new Flags({ - flags: {}, - defaultFlagHandler: this.default_flag_handler - }); - } - - throw e; - } - } - - private async _get_identity_flags_from_api(identifier: string, traits: { [key: string]: any }) { - try { - const data = generate_identities_data(identifier, traits); - const jsonResponse = await this._get_json_response(this.identities_url, 'POST', data); - return Flags.fromAPIFlags({ - apiFlags: jsonResponse['flags'], - analyticsProcessor: this._analytics_processor, - defaultFlagHandler: this.default_flag_handler - }); - } catch (e) { - if (this.default_flag_handler) { - return new Flags({ - flags: {}, - defaultFlagHandler: this.default_flag_handler - }); - } - - throw e; - } - } - - private _build_identity_model(identifier: string, traits: any[]) { - if (!this.environment) { - throw new FlagsmithClientError( - 'Unable to build identity model when no local environment present.' - ); - } - - const traitModels = traits.map(trait => new TraitModel(trait.key, trait.value)); - return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); - } - - stop() {} -} diff --git a/sdk/index.ts b/sdk/index.ts index e69de29..e8bf0ee 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -0,0 +1,225 @@ +import fetch from 'node-fetch'; +import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine'; +import { EnvironmentModel } from '../flagsmith-engine/environments/models'; +import { buildEnvironmentModel } from '../flagsmith-engine/environments/util'; +import { IdentityModel } from '../flagsmith-engine/identities/models'; +import { TraitModel } from '../flagsmith-engine/identities/traits/models'; + +import { AnalyticsProcessor } from './analytics'; +import { FlagsmithAPIError, FlagsmithClientError } from './errors'; + +import { DefaultFlag, Flags } from './models'; +import { EnvironmentDataPollingManager } from './polling_manager'; +import { generateIdentitiesData } from './utils'; + +const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; + +export class Flagsmith { + environmentKey?: string; + apiUrl: string = DEFAULT_API_URL; + customHeaders?: { [key: string]: any }; + requestTimeoutSeconds?: number; + enableLocalEvaluation?: boolean = false; + environmentRefreshIntervalSeconds: number = 60; + retries?: any; + enableAnalytics: boolean = false; + defaultFlagHandler?: (featureName: string) => DefaultFlag; + + environmentFlagsUrl: string; + identitiesUrl: string; + environmentUrl: string; + + environmentDataPollingManager?: EnvironmentDataPollingManager; + environment?: EnvironmentModel; + private analyticsProcessor?: AnalyticsProcessor; + + constructor(data: { + environmentKey: string; + apiUrl?: string; + customHeaders?: { [key: string]: any }; + requestTimeoutSeconds?: number; + enableLocalEvaluation?: boolean; + environmentRefreshIntervalSeconds?: number; + retries?: any; + enableAnalytics?: boolean; + defaultFlagHandler?: (featureName: string) => DefaultFlag; + }) { + this.environmentKey = data.environmentKey; + this.apiUrl = data.apiUrl || this.apiUrl; + this.customHeaders = data.customHeaders; + this.requestTimeoutSeconds = data.requestTimeoutSeconds; + this.enableLocalEvaluation = data.enableLocalEvaluation; + this.environmentRefreshIntervalSeconds = + data.environmentRefreshIntervalSeconds || this.environmentRefreshIntervalSeconds; + this.retries = data.retries; + this.enableAnalytics = data.enableAnalytics || false; + this.defaultFlagHandler = data.defaultFlagHandler; + + this.environmentFlagsUrl = `${this.apiUrl}flags/`; + this.identitiesUrl = `${this.apiUrl}identities/`; + this.environmentUrl = `${this.apiUrl}environment-document/`; + + this.environment; + if (this.enableLocalEvaluation) { + this.environmentDataPollingManager = new EnvironmentDataPollingManager( + this, + this.environmentRefreshIntervalSeconds + ); + this.environmentDataPollingManager.start(); + } + + this.analyticsProcessor = data.enableAnalytics + ? new AnalyticsProcessor({ + environmentKey: this.environmentKey, + baseApiUrl: this.apiUrl, + timeout: this.requestTimeoutSeconds + }) + : undefined; + } + + async getEnvironmentFlags(): Promise { + if (this.environment) { + return new Promise(resolve => resolve(this.getEnvironmentFlagsFromDocument())); + } + + return this.getEnvironmentFlagsFromApi(); + } + + getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { + traits = traits || {}; + if (this.environment) { + return new Promise(resolve => + resolve(this.getIdentityFlagsFromDocument(identifier, traits || {})) + ); + } + return this.getIdentityFlagsFromApi(identifier, traits); + } + + async update_environment() { + this.environment = await this.getEnvironmentFromApi(); + } + + private async getJSONResponse( + url: string, + method: string, + body?: { [key: string]: any } + ): Promise { + const headers: { [key: string]: any } = {}; + if (this.environmentKey) { + headers['X-Environment-Key'] = this.environmentKey as string; + } + + if (this.customHeaders) { + for (const [k, v] of Object.entries(this.customHeaders)) { + headers[k] = v; + } + } + + const data = await fetch(url, { + method: method, + timeout: this.requestTimeoutSeconds || undefined, + body: JSON.stringify(body), + headers: headers + }); + + if (data.status !== 200) { + throw new FlagsmithAPIError( + `Invalid request made to Flagsmith API. Response status code: ${data.status}` + ); + } + + return data.json(); + } + + private async getEnvironmentFromApi() { + const environment_data = await this.getJSONResponse(this.environmentUrl, 'GET'); + return buildEnvironmentModel(environment_data); + } + + private getEnvironmentFlagsFromDocument() { + if (!this.environment) { + throw new FlagsmithClientError( + 'Unable to build identity model when no local environment present.' + ); + } + + return Flags.fromFeatureStateModels({ + featureStates: getEnvironmentFeatureStates(this.environment), + analyticsProcessor: this.analyticsProcessor, + defaultFlagHandler: this.defaultFlagHandler + }); + } + + private getIdentityFlagsFromDocument(identifier: string, traits: { [key: string]: any }) { + if (!this.environment) { + throw new FlagsmithClientError( + 'Unable to build identity model when no local environment present.' + ); + } + + const identityModel = this.buildIdentityModel(identifier, Object.values(traits)); + const featureStates = getIdentityFeatureStates(this.environment, identityModel); + + return Flags.fromFeatureStateModels({ + featureStates: featureStates, + analyticsProcessor: this.analyticsProcessor, + defaultFlagHandler: this.defaultFlagHandler + }); + } + + private async getEnvironmentFlagsFromApi() { + try { + const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET'); + return Flags.fromAPIFlags({ + apiFlags: apiFlags, + analyticsProcessor: this.analyticsProcessor, + defaultFlagHandler: this.defaultFlagHandler + }); + } catch (e) { + if (this.defaultFlagHandler) { + return new Flags({ + flags: {}, + defaultFlagHandler: this.defaultFlagHandler + }); + } + + throw e; + } + } + + private async getIdentityFlagsFromApi(identifier: string, traits: { [key: string]: any }) { + try { + const data = generateIdentitiesData(identifier, traits); + const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data); + return Flags.fromAPIFlags({ + apiFlags: jsonResponse['flags'], + analyticsProcessor: this.analyticsProcessor, + defaultFlagHandler: this.defaultFlagHandler + }); + } catch (e) { + if (this.defaultFlagHandler) { + return new Flags({ + flags: {}, + defaultFlagHandler: this.defaultFlagHandler + }); + } + + throw e; + } + } + + private buildIdentityModel(identifier: string, traits: any[]) { + if (!this.environment) { + throw new FlagsmithClientError( + 'Unable to build identity model when no local environment present.' + ); + } + + const traitModels = traits.map(trait => new TraitModel(trait.key, trait.value)); + return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); + } + + stop() {} +} + +export default Flagsmith; diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts index 37eee65..68dc142 100644 --- a/sdk/polling_manager.ts +++ b/sdk/polling_manager.ts @@ -1,4 +1,4 @@ -import { Flagsmith } from './flagsmith'; +import { Flagsmith } from '.'; export class EnvironmentDataPollingManager { private interval?: NodeJS.Timer; diff --git a/sdk/utils.ts b/sdk/utils.ts index ef24f75..4303666 100644 --- a/sdk/utils.ts +++ b/sdk/utils.ts @@ -1,4 +1,4 @@ -export function generate_identities_data(identifier: string, traits?: { [key: string]: any }) { +export function generateIdentitiesData(identifier: string, traits?: { [key: string]: any }) { const traitsGenerated = Object.values(traits || {}).map(trait => ({ trait_key: trait[0], trait_value: trait[1] diff --git a/tests/sdk/analytics.test.ts b/tests/sdk/analytics.test.ts index 82d3969..7bd106f 100644 --- a/tests/sdk/analytics.test.ts +++ b/tests/sdk/analytics.test.ts @@ -9,17 +9,17 @@ afterEach(() => { test('test_analytics_processor_track_feature_updates_analytics_data', () => { const aP = analyticsProcessor(); aP.trackFeature(1); - expect(aP.analytics_data[1]).toBe(1); + expect(aP.analyticsData[1]).toBe(1); aP.trackFeature(1); - expect(aP.analytics_data[1]).toBe(2); + expect(aP.analyticsData[1]).toBe(2); }); test('test_analytics_processor_flush_clears_analytics_data', async () => { const aP = analyticsProcessor(); aP.trackFeature(1); await aP.flush(); - expect(aP.analytics_data).toStrictEqual({}); + expect(aP.analyticsData).toStrictEqual({}); }); test('test_analytics_processor_flush_post_request_data_match_ananlytics_data', async () => { diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 0a4ea19..437a167 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -1,4 +1,4 @@ -import { Flagsmith } from '../../sdk/flagsmith'; +import { Flagsmith } from '../../sdk'; import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; import fetch, { Headers } from 'node-fetch'; import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils'; @@ -15,8 +15,8 @@ beforeEach(() => { test('test_flagsmith_starts_polling_manager_on_init_if_enabled', () => { new Flagsmith({ - environment_key: 'key', - enable_local_evaluation: true + environmentKey: 'key', + enableLocalEvaluation: true }); expect(EnvironmentDataPollingManager).toBeCalled(); }); @@ -98,8 +98,8 @@ test('test_default_flag_is_used_when_no_environment_flags_returned', async () => const defaultFlagHandler = (featureName: string) => defaultFlag; const flg = new Flagsmith({ - environment_key: 'key', - default_flag_handler: defaultFlagHandler + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler }); const flags = await flg.getEnvironmentFlags(); @@ -117,7 +117,7 @@ test('test_non_200_response_raises_flagsmith_api_error', async () => { fetch.mockReturnValue(Promise.resolve(errorResponse403)); const flg = new Flagsmith({ - environment_key: 'some' + environmentKey: 'some' }); await expect(flg.getEnvironmentFlags()).rejects.toThrow(); @@ -131,8 +131,8 @@ test('test_default_flag_is_not_used_when_environment_flags_returned', async () = const defaultFlagHandler = (featureName: string) => defaultFlag; const flg = new Flagsmith({ - environment_key: 'key', - default_flag_handler: defaultFlagHandler + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler }); const flags = await flg.getEnvironmentFlags(); @@ -151,8 +151,8 @@ test('test_default_flag_is_not_used_when_identity_flags_returned', async () => { const defaultFlagHandler = (featureName: string) => defaultFlag; const flg = new Flagsmith({ - environment_key: 'key', - default_flag_handler: defaultFlagHandler + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler }); const flags = await flg.getIdentityFlags('identifier'); @@ -171,8 +171,8 @@ test('test_default_flag_is_used_when_no_identity_flags_returned', async () => { const defaultFlagHandler = (featureName: string) => defaultFlag; const flg = new Flagsmith({ - environment_key: 'key', - default_flag_handler: defaultFlagHandler + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler }); const flags = await flg.getIdentityFlags('identifier'); diff --git a/tests/sdk/polling.test.ts b/tests/sdk/polling.test.ts index 0a58e85..34078af 100644 --- a/tests/sdk/polling.test.ts +++ b/tests/sdk/polling.test.ts @@ -1,6 +1,6 @@ -import { Flagsmith } from '../../sdk/flagsmith'; +import { Flagsmith } from '../../sdk'; import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; -jest.mock('../../sdk/flagsmith'); +jest.mock('../../sdk'); jest.mock('node-fetch'); beforeEach(() => { @@ -16,7 +16,7 @@ function sleep(ms: number) { test('test_polling_manager_calls_update_environment_on_start', async () => { const flagsmith = new Flagsmith({ - environment_key: 'key' + environmentKey: 'key' }); const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); @@ -28,7 +28,7 @@ test('test_polling_manager_calls_update_environment_on_start', async () => { test('test_polling_manager_calls_update_environment_on_each_refresh', async () => { const flagsmith = new Flagsmith({ - environment_key: 'key' + environmentKey: 'key' }); const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); diff --git a/tests/sdk/utils.ts b/tests/sdk/utils.ts index 887cec4..8fe921d 100644 --- a/tests/sdk/utils.ts +++ b/tests/sdk/utils.ts @@ -1,14 +1,14 @@ import { readFileSync } from 'fs'; import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util'; import { AnalyticsProcessor } from '../../sdk/analytics'; -import { Flagsmith } from '../../sdk/flagsmith'; +import { Flagsmith } from '../../sdk'; const DATA_DIR = __dirname + '/data/'; export function analyticsProcessor() { return new AnalyticsProcessor({ - environment_key: 'test-key', - base_api_url: 'http://testUrl' + environmentKey: 'test-key', + baseApiUrl: 'http://testUrl' }); } @@ -18,7 +18,7 @@ export function apiKey(): string { export function flagsmith() { return new Flagsmith({ - environment_key: apiKey() + environmentKey: apiKey() }); } From d1c963187ad271d7d00fc6ec71f7495c38db3e00 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 04:01:27 +0200 Subject: [PATCH 05/56] docs: add JSDoc comments for the SDK --- sdk/analytics.ts | 16 +++++++++++-- sdk/index.ts | 59 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/sdk/analytics.ts b/sdk/analytics.ts index 8cf1d75..b4181ce 100644 --- a/sdk/analytics.ts +++ b/sdk/analytics.ts @@ -1,6 +1,8 @@ import fetch from 'node-fetch'; const ANALYTICS_ENDPOINT = 'analytics/flags/'; + +// Used to control how often we send data(in seconds) const ANALYTICS_TIMER = 10; export class AnalyticsProcessor { @@ -9,7 +11,15 @@ export class AnalyticsProcessor { private lastFlushed: number; analyticsData: { [key: string]: any }; private timeout: number = 3; - + /** + * AnalyticsProcessor is used to track how often individual Flags are evaluated within + * the Flagsmith SDK. Docs: https://docs.flagsmith.com/advanced-use/flag-analytics. + * + * @param data.environmentKey environment key obtained from the Flagsmith UI + * @param data.baseApiUrl base api url to override when using self hosted version + * @param data.timeout used to tell requests to stop waiting for a response after a + given number of seconds + */ constructor(data: { environmentKey: string; baseApiUrl: string; timeout?: number }) { this.analyticsEndpoint = data.baseApiUrl + ANALYTICS_ENDPOINT; this.environmentKey = data.environmentKey; @@ -17,7 +27,9 @@ export class AnalyticsProcessor { this.analyticsData = {}; this.timeout = data.timeout || this.timeout; } - + /** + * Sends all the collected data to the api asynchronously and resets the timer + */ async flush() { if (!Object.keys(this.analyticsData).length) { return; diff --git a/sdk/index.ts b/sdk/index.ts index e8bf0ee..83d3898 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -32,7 +32,36 @@ export class Flagsmith { environmentDataPollingManager?: EnvironmentDataPollingManager; environment?: EnvironmentModel; private analyticsProcessor?: AnalyticsProcessor; - + /** + * A Flagsmith client. + * + * Provides an interface for interacting with the Flagsmith http API. + * Basic Usage:: + * + * import flagsmith from Flagsmith + * const flagsmith = new Flagsmith({environmentKey: ''}); + * const environmentFlags = flagsmith.getEnvironmentFlags(); + * const featureEnabled = environmentFlags.isFeatureEnabled('foo'); + * const identityFlags = flagsmith.getIdentityFlags('identifier', {'foo': 'bar'}); + * const featureEnabledForIdentity = identityFlags.isFeatureEnabled("foo") + * + * @param {string} data.environmentKey: The environment key obtained from Flagsmith interface + @param {string} data.apiUrl: Override the URL of the Flagsmith API to communicate with + @param data.customHeaders: Additional headers to add to requests made to the + Flagsmith API + @param {number} data.requestTimeoutSeconds: Number of seconds to wait for a request to + complete before terminating the request + @param {boolean} data.enableLocalEvaluation: Enables local evaluation of flags + @param {number} data.environmentRefreshIntervalSeconds: If using local evaluation, + specify the interval period between refreshes of local environment data + @param {number} data.retries: a urllib3.Retry object to use on all http requests to the + Flagsmith API + @param {boolean} data.enableAnalytics: if enabled, sends additional requests to the Flagsmith + API to power flag analytics charts + @param data.defaultFlagHandler: callable which will be used in the case where + flags cannot be retrieved from the API or a non existent feature is + requested + */ constructor(data: { environmentKey: string; apiUrl?: string; @@ -70,13 +99,17 @@ export class Flagsmith { this.analyticsProcessor = data.enableAnalytics ? new AnalyticsProcessor({ - environmentKey: this.environmentKey, - baseApiUrl: this.apiUrl, - timeout: this.requestTimeoutSeconds - }) + environmentKey: this.environmentKey, + baseApiUrl: this.apiUrl, + timeout: this.requestTimeoutSeconds + }) : undefined; } - + /** + * Get all the default for flags for the current environment. + * + * @returns Flags object holding all the flags for the current environment. + */ async getEnvironmentFlags(): Promise { if (this.environment) { return new Promise(resolve => resolve(this.getEnvironmentFlagsFromDocument())); @@ -84,7 +117,17 @@ export class Flagsmith { return this.getEnvironmentFlagsFromApi(); } - + /** + * Get all the flags for the current environment for a given identity. Will also + upsert all traits to the Flagsmith API for future evaluations. Providing a + trait with a value of None will remove the trait from the identity if it exists. + * + * @param {string} identifier a unique identifier for the identity in the current + environment, e.g. email address, username, uuid + * @param {{[key:string]:any}} traits? a dictionary of traits to add / update on the identity in + Flagsmith, e.g. {"num_orders": 10} + * @returns Flags object holding all the flags for the given identity. + */ getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { traits = traits || {}; if (this.environment) { @@ -219,7 +262,7 @@ export class Flagsmith { return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); } - stop() {} + stop() { } } export default Flagsmith; From 3c7de37bce958e66a7dadb6beb0334a985112c93 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 04:14:55 +0200 Subject: [PATCH 06/56] docs: update example of SDK usage --- .husky/pre-commit | 2 +- example/server/api/index.js | 24 ++-- flagsmith-core.js | 243 ------------------------------------ index.d.ts | 85 ------------- index.js | 3 - index.ts | 3 + package.json | 1 + sdk/index.ts | 14 ++- tsconfig.json | 3 +- 9 files changed, 22 insertions(+), 356 deletions(-) delete mode 100644 flagsmith-core.js delete mode 100644 index.d.ts delete mode 100644 index.js create mode 100644 index.ts diff --git a/.husky/pre-commit b/.husky/pre-commit index 69d7abf..91f385a 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,5 +2,5 @@ . "$(dirname "$0")/_/husky.sh" npm run lint -git add ./flagsmith-engine ./tests +git add ./flagsmith-engine ./sdk ./tests npm run test \ No newline at end of file diff --git a/example/server/api/index.js b/example/server/api/index.js index cbcd75e..0af0dad 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -1,32 +1,22 @@ const Router = require('express').Router; -const environmentID = 'uCDQzKWgejrutqSYYsKWen'; -const flagsmith = require('../../../'); -const NodeCache = require('node-cache'); +const { Flagsmith } = require('../../../sdk'); -flagsmith.init({ - environmentID - // this is an example of a user-defined cache - /*cache: new NodeCache({ - stdTTL: 5 - })*/ +const flagsmith = new Flagsmith({ + environmentKey: 'some-key', }); module.exports = () => { const api = Router(); api.get('/', async (req, res) => { - const font_size = await flagsmith.getValue('font_size'); - res.json({ font_size }); - }); - - api.get('/flags', async (req, res) => { - const flags = await flagsmith.getFlags(); + const flags = await flagsmith.getEnvironmentFlags(); res.json(flags); }); api.get('/:user', async (req, res) => { - const font_size = await flagsmith.getValue('font_size', req.params.user); - res.json({ font_size }); + const flags = await flagsmith.getIdentityFlags(req.params.user); + const fontSize = flags.getFeatureValue('font_size'); + res.json({ fontSize }); }); return api; diff --git a/flagsmith-core.js b/flagsmith-core.js deleted file mode 100644 index 8456fd8..0000000 --- a/flagsmith-core.js +++ /dev/null @@ -1,243 +0,0 @@ -let fetch = require('node-fetch'); -// https://github.com/node-fetch/node-fetch/issues/450 -if (typeof fetch.default !== 'undefined') fetch = fetch.default; - -module.exports = class FlagsmithCore { - normalizeFlags(flags) { - const _flags = {}; - - for (const { feature, enabled, feature_state_value } of flags) { - const normalizedKey = feature.name.toLowerCase().replace(/ /g, '_'); - _flags[normalizedKey] = { - enabled, - value: feature_state_value - }; - } - - return _flags; - } - - normalizeTraits(traits) { - const _traits = {}; - - for (const { trait_key, trait_value } of traits) { - const normalizedKey = trait_key.toLowerCase().replace(/ /g, '_'); - _traits[normalizedKey] = trait_value; - } - - return _traits; - } - - async getJSON(url, method, body) { - const { environmentID } = this; - const options = { - method: method || 'GET', - body, - headers: { - 'x-environment-key': environmentID - } - }; - - if (method !== 'GET') { - options.headers['Content-Type'] = 'application/json; charset=utf-8'; - } - - const res = await fetch(url, options); - const result = await res.json(); - - if (res.status >= 400) { - throw new Error(result.detail); - } - - return result; - } - - init({ environmentID, api, onError, cache }) { - if (!environmentID) { - throw new Error('Please specify a environment id'); - } - - this.environmentID = environmentID; - - this.api = api || 'https://api.flagsmith.com/api/v1'; - this.onError = onError; - - if (cache) { - const missingMethods = []; - - ['has', 'get', 'set'].forEach(method => { - if (!cache[method]) missingMethods.push(method); - }); - - if (missingMethods.length > 0) { - throw new Error( - `Please implement the following methods in your cache: ${missingMethods.join( - ', ' - )}` - ); - } - } - - this.cache = cache; - } - - async getFlags() { - if (this.cache && (await this.cache.has('flags'))) { - return this.cache.get('flags'); - } - - const { onError, api } = this; - - try { - const flags = await this.getJSON(`${api}/flags/`); - const normalizedFlags = this.normalizeFlags(flags); - - if (this.cache) await this.cache.set('flags', normalizedFlags); - - return normalizedFlags; - } catch (err) { - onError && onError({ message: err.message }); - throw err; - } - } - - async getFlagsForUser(identity) { - const cacheKey = `flags-${identity}`; - - if (this.cache && (await this.cache.has(cacheKey))) { - return this.cache.get(cacheKey); - } - - const { onError, api } = this; - - if (!identity) { - const errMsg = 'getFlagsForUser() called without a user identity'; - onError && onError({ message: errMsg }); - throw new Error(errMsg); - } - - try { - const { flags } = await this.getJSON(`${api}/identities/?identifier=${identity}`); - const normalizedFlags = this.normalizeFlags(flags); - - if (this.cache) await this.cache.set(cacheKey, normalizedFlags); - - return normalizedFlags; - } catch (err) { - onError && onError({ message: err.message }); - throw err; - } - } - - async getUserIdentity(identity) { - const cacheKey = `flags_traits-${identity}`; - - if (this.cache && (await this.cache.has(cacheKey))) { - return this.cache.get(cacheKey); - } - - const { onError, api } = this; - - if (!identity) { - const errMsg = 'getUserIdentity() called without a user identity'; - onError && onError({ message: errMsg }); - throw new Error(errMsg); - } - - try { - const { flags, traits } = await this.getJSON( - `${api}/identities/?identifier=${identity}` - ); - - const normalizedFlags = this.normalizeFlags(flags); - const normalizedTraits = this.normalizeTraits(traits); - const res = { flags: normalizedFlags, traits: normalizedTraits }; - - if (this.cache) await this.cache.set(cacheKey, res); - - return res; - } catch (err) { - onError && onError({ message: err.message }); - throw err; - } - } - - async getValue(key, userId) { - const flags = userId ? await this.getFlagsForUser(userId) : await this.getFlags(); - - return this.getValueFromFeatures(key, flags); - } - - async hasFeature(key, userId) { - const flags = userId ? await this.getFlagsForUser(userId) : await this.getFlags(); - - return this.checkFeatureEnabled(key, flags); - } - - getValueFromFeatures(key, flags) { - if (!flags) return null; - - const flag = flags[key]; - - //todo record check for value - return flag ? flag.value : null; - } - - checkFeatureEnabled(key, flags) { - if (!flags) return false; - - const flag = flags[key]; - return flag && flag.enabled; - } - - async getTrait(identity, key) { - const { onError } = this; - - if (!identity || !key) { - const errMsg = `getTrait() called without a ${ - !identity ? 'user identity' : 'trait key' - }`; - onError && onError({ message: errMsg }); - throw new Error(errMsg); - } - - try { - const { traits } = await this.getUserIdentity(identity); - return traits[key]; - } catch (err) { - onError && onError({ message: err.message }); - throw err; - } - } - - async setTrait(identity, key, value) { - const { onError, api } = this; - - if (!identity || !key) { - const errMsg = `setTrait() called without a ${ - !identity ? 'user identity' : 'trait key' - }`; - onError && - onError({ - message: errMsg - }); - throw new Error(errMsg); - } - - const body = { - identity: { - identifier: identity - }, - trait_key: key, - trait_value: value - }; - - try { - await this.getJSON(`${api}/traits/`, 'POST', JSON.stringify(body)); - return await this.getUserIdentity(identity); - } catch (err) { - onError && onError({ message: err.message }); - throw err; - } - } -}; diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index eeac23b..0000000 --- a/index.d.ts +++ /dev/null @@ -1,85 +0,0 @@ -declare module 'flagsmith-nodejs' { - /** - * Initialise the sdk against a particular environment - */ - export function init(config: { - environmentID: string; - onError?: Function; - defaultFlags?: string[]; - api?: string; - cache?: ICache; - }): void; - - /** - * Get the whether a flag is enabled e.g. flagsmith.hasFeature("powerUserFeature") - */ - export function hasFeature(key: string): Promise; - - /** - * Get the value of a whether a flag is enabled for a user e.g. flagsmith.hasFeature("powerUserFeature", 1234) - */ - export function hasFeature(key: string, userId: string): Promise; - - /** - * Get the value of a particular remote config e.g. flagsmith.getValue("font_size") - */ - export function getValue(key: string): Promise; - - /** - * Get the value of a particular remote config for a specified user e.g. flagsmith.getValue("font_size", 1234) - */ - export function getValue(key: string, userId: string): Promise; - - /** - * Trigger a manual fetch of the environment features - */ - export function getFlags(): Promise; - - /** - * Trigger a manual fetch of the environment features for a given user id - */ - export function getFlagsForUser(userId: string): Promise; - - /** - * Trigger a manual fetch of both the environment features and users' traits for a given user id - */ - export function getUserIdentity(userId: string): Promise; - - /** - * Trigger a manual fetch of a specific trait for a given user id - */ - export function getTrait(userId: string, key: string): Promise; - - /** - * Set a specific trait for a given user id - */ - export function setTrait( - userId: string, - key: string, - value: string | number | boolean - ): IUserIdentity; - - interface IFeature { - enabled: boolean; - value?: string | number | boolean; - } - - interface IFlags { - [key: string]: IFeature; - } - - interface ITraits { - [key: string]: string; - } - - interface IUserIdentity { - flags: IFeature; - traits: ITraits; - } - - interface ICache { - has(key: string): boolean | Promise; - get(key: string): any | Promise; - set(key: string, val: any): void | Promise; - } -} diff --git a/index.js b/index.js deleted file mode 100644 index 54eefae..0000000 --- a/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const FlagsmithCore = require('./flagsmith-core'); - -module.exports = new FlagsmithCore(); diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..eb39c94 --- /dev/null +++ b/index.ts @@ -0,0 +1,3 @@ +import Flagsmith from "./sdk"; + +export default Flagsmith; \ No newline at end of file diff --git a/package.json b/package.json index c622af0..32d8e83 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "scripts": { "lint": "prettier --write .", "test": "jest --coverage --coverageReporters='text'", + "build": "tsc", "prepare": "husky install" }, "dependencies": { diff --git a/sdk/index.ts b/sdk/index.ts index 83d3898..3ab5f0a 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -12,6 +12,8 @@ import { DefaultFlag, Flags } from './models'; import { EnvironmentDataPollingManager } from './polling_manager'; import { generateIdentitiesData } from './utils'; +// @ts-ignore +if (typeof fetch.default !== 'undefined') fetch = fetch.default; const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; export class Flagsmith { @@ -99,15 +101,15 @@ export class Flagsmith { this.analyticsProcessor = data.enableAnalytics ? new AnalyticsProcessor({ - environmentKey: this.environmentKey, - baseApiUrl: this.apiUrl, - timeout: this.requestTimeoutSeconds - }) + environmentKey: this.environmentKey, + baseApiUrl: this.apiUrl, + timeout: this.requestTimeoutSeconds + }) : undefined; } /** * Get all the default for flags for the current environment. - * + * * @returns Flags object holding all the flags for the current environment. */ async getEnvironmentFlags(): Promise { @@ -262,7 +264,7 @@ export class Flagsmith { return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); } - stop() { } + stop() {} } export default Flagsmith; diff --git a/tsconfig.json b/tsconfig.json index 9195571..777e51c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,8 @@ { "include": [ "./flagsmith-engine", - "./sdk" + "./sdk", + "./index.ts" ], "compilerOptions": { "outDir": "./build", From 869107e1d34b5e8a1e033aa7b00b9b02fe1299e9 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 04:16:57 +0200 Subject: [PATCH 07/56] chore: add example to precommit linting --- .husky/pre-commit | 2 +- example/server/api/index.js | 2 +- index.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 91f385a..1218e87 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,5 +2,5 @@ . "$(dirname "$0")/_/husky.sh" npm run lint -git add ./flagsmith-engine ./sdk ./tests +git add ./flagsmith-engine ./sdk ./tests ./example ./index.ts npm run test \ No newline at end of file diff --git a/example/server/api/index.js b/example/server/api/index.js index 0af0dad..04809a7 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -2,7 +2,7 @@ const Router = require('express').Router; const { Flagsmith } = require('../../../sdk'); const flagsmith = new Flagsmith({ - environmentKey: 'some-key', + environmentKey: 'some-key' }); module.exports = () => { diff --git a/index.ts b/index.ts index eb39c94..b25c6c5 100644 --- a/index.ts +++ b/index.ts @@ -1,3 +1,3 @@ -import Flagsmith from "./sdk"; +import Flagsmith from './sdk'; -export default Flagsmith; \ No newline at end of file +export default Flagsmith; From 2c9d5545dd99f11f751bd85801a2e26b8401a1ed Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 14:01:23 +0200 Subject: [PATCH 08/56] chore: add gh action for tests --- .github/workflows/pull_request.yaml | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/pull_request.yaml diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml new file mode 100644 index 0000000..ba9db97 --- /dev/null +++ b/.github/workflows/pull_request.yaml @@ -0,0 +1,33 @@ +name: Unit/Integration Tests + +on: + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review + push: + branches: + - sdk-rewrite +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: '15.x' + - name: cache node modules + uses: actions/cache@v1 + with: + path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS + key: npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + npm-${{ hashFiles('package-lock.json') }} + npm- + - run: npm i -g npm@7.0.2 + - run: npm install + - run: npm test + env: + CI: true From 3a11cbe585272f547ffa17bc94125836aabfcc58 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 10 Mar 2022 14:04:41 +0200 Subject: [PATCH 09/56] chore: trigger tests when pushed to main --- .github/workflows/pull_request.yaml | 2 +- .husky/pre-commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index ba9db97..ef1766f 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -9,7 +9,7 @@ on: - ready_for_review push: branches: - - sdk-rewrite + - main jobs: build-and-test: runs-on: ubuntu-latest diff --git a/.husky/pre-commit b/.husky/pre-commit index 1218e87..7954841 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,5 +2,5 @@ . "$(dirname "$0")/_/husky.sh" npm run lint -git add ./flagsmith-engine ./sdk ./tests ./example ./index.ts +git add ./flagsmith-engine ./sdk ./tests ./example ./index.ts ./.github npm run test \ No newline at end of file From ffd8e1d6f973cab2f6d9468fd8892da1dcf3375e Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Fri, 11 Mar 2022 00:05:50 +0200 Subject: [PATCH 10/56] fix: retry logic for sdk --- sdk/analytics.ts | 30 ++++++++++++++++++++++++++++++ sdk/index.ts | 23 +++++++++++++---------- sdk/utils.ts | 35 +++++++++++++++++++++++++++++++++++ tests/sdk/polling.test.ts | 11 +++-------- 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/sdk/analytics.ts b/sdk/analytics.ts index b4181ce..9d406c5 100644 --- a/sdk/analytics.ts +++ b/sdk/analytics.ts @@ -5,6 +5,36 @@ const ANALYTICS_ENDPOINT = 'analytics/flags/'; // Used to control how often we send data(in seconds) const ANALYTICS_TIMER = 10; +const delay = (ms: number) => new Promise(resolve => setTimeout(() => resolve(undefined), ms)); + +const retryFetch = ( + url: string, + fetchOptions = {}, + retries = 3, + retryDelay = 1000, + timeout: number +) => { + return new Promise((resolve, reject) => { + // check for timeout + if (timeout) setTimeout(() => reject('error: timeout'), timeout); + + const wrapper = (n: number) => { + fetch(url, fetchOptions) + .then(res => resolve(res)) + .catch(async err => { + if (n > 0) { + await delay(retryDelay); + wrapper(--n); + } else { + reject(err); + } + }); + }; + + wrapper(retries); + }); +}; + export class AnalyticsProcessor { private analyticsEndpoint: string; private environmentKey: string; diff --git a/sdk/index.ts b/sdk/index.ts index 3ab5f0a..952996d 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -1,4 +1,3 @@ -import fetch from 'node-fetch'; import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine'; import { EnvironmentModel } from '../flagsmith-engine/environments/models'; import { buildEnvironmentModel } from '../flagsmith-engine/environments/util'; @@ -10,10 +9,8 @@ import { FlagsmithAPIError, FlagsmithClientError } from './errors'; import { DefaultFlag, Flags } from './models'; import { EnvironmentDataPollingManager } from './polling_manager'; -import { generateIdentitiesData } from './utils'; +import { generateIdentitiesData, retryFetch } from './utils'; -// @ts-ignore -if (typeof fetch.default !== 'undefined') fetch = fetch.default; const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; export class Flagsmith { @@ -160,12 +157,18 @@ export class Flagsmith { } } - const data = await fetch(url, { - method: method, - timeout: this.requestTimeoutSeconds || undefined, - body: JSON.stringify(body), - headers: headers - }); + const data = await retryFetch( + url, + { + method: method, + timeout: this.requestTimeoutSeconds || undefined, + body: JSON.stringify(body), + headers: headers + }, + this.retries, + 1000, + (this.requestTimeoutSeconds || 10) * 1000 + ); if (data.status !== 200) { throw new FlagsmithAPIError( diff --git a/sdk/utils.ts b/sdk/utils.ts index 4303666..259a229 100644 --- a/sdk/utils.ts +++ b/sdk/utils.ts @@ -1,3 +1,7 @@ +import fetch, { Response } from 'node-fetch'; +// @ts-ignore +if (typeof fetch.default !== 'undefined') fetch = fetch.default; + export function generateIdentitiesData(identifier: string, traits?: { [key: string]: any }) { const traitsGenerated = Object.values(traits || {}).map(trait => ({ trait_key: trait[0], @@ -8,3 +12,34 @@ export function generateIdentitiesData(identifier: string, traits?: { [key: stri traits: traitsGenerated }; } + +export const delay = (ms: number) => + new Promise(resolve => setTimeout(() => resolve(undefined), ms)); + +export const retryFetch = ( + url: string, + fetchOptions = {}, + retries = 3, + retryDelay = 1000, + timeout: number +): Promise => { + return new Promise((resolve, reject) => { + // check for timeout + if (timeout) setTimeout(() => reject('error: timeout'), timeout); + + const wrapper = (n: number) => { + fetch(url, fetchOptions) + .then(res => resolve(res)) + .catch(async err => { + if (n > 0) { + await delay(retryDelay); + wrapper(--n); + } else { + reject(err); + } + }); + }; + + wrapper(retries); + }); +}; diff --git a/tests/sdk/polling.test.ts b/tests/sdk/polling.test.ts index 34078af..9be49c9 100644 --- a/tests/sdk/polling.test.ts +++ b/tests/sdk/polling.test.ts @@ -1,5 +1,6 @@ import { Flagsmith } from '../../sdk'; import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; +import { delay } from '../../sdk/utils'; jest.mock('../../sdk'); jest.mock('node-fetch'); @@ -8,12 +9,6 @@ beforeEach(() => { Flagsmith.mockClear(); }); -function sleep(ms: number) { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} - test('test_polling_manager_calls_update_environment_on_start', async () => { const flagsmith = new Flagsmith({ environmentKey: 'key' @@ -21,7 +16,7 @@ test('test_polling_manager_calls_update_environment_on_start', async () => { const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); pollingManager.start(); - await sleep(500); + await delay(500); pollingManager.stop(); expect(flagsmith.update_environment).toHaveBeenCalled(); }); @@ -33,7 +28,7 @@ test('test_polling_manager_calls_update_environment_on_each_refresh', async () = const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); pollingManager.start(); - await sleep(450); + await delay(450); pollingManager.stop(); expect(flagsmith.update_environment).toHaveBeenCalledTimes(3); }); From 5dba29583579118c685ee37d3ab1e3982edd594a Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Mon, 14 Mar 2022 12:30:33 +0000 Subject: [PATCH 11/56] SDK Fixes --- example/README.md | 6 ------ example/package.json | 2 +- example/server/api/index.js | 13 +++++++++---- example/server/index.js | 10 ++++------ sdk/index.ts | 18 ++++++++++++------ sdk/polling_manager.ts | 5 +++-- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/example/README.md b/example/README.md index c221528..55a62de 100644 --- a/example/README.md +++ b/example/README.md @@ -2,12 +2,6 @@ ## Getting Started -# Setup via cli - -`npm i ssg-node -g` - -`ssg-node PROJECT_NAME` - # Run `$ npm start` diff --git a/example/package.json b/example/package.json index 95b32c6..14e6fae 100644 --- a/example/package.json +++ b/example/package.json @@ -4,7 +4,7 @@ "description": "Node Express Boilerplate", "main": "index.js", "scripts": { - "start": "node --inspect ./server", + "start": "cd ../ && npm run build && cd ./example && node --inspect ./server", "dev": "nodemon --exec npm start", "test": "nodemon ./server/tests/" }, diff --git a/example/server/api/index.js b/example/server/api/index.js index 04809a7..7a27002 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -1,8 +1,12 @@ const Router = require('express').Router; -const { Flagsmith } = require('../../../sdk'); +const { Flagsmith } = require('../../../build/sdk'); const flagsmith = new Flagsmith({ - environmentKey: 'some-key' + environmentKey: 'ser.dCxh8XoQc3Sw3JqMqMbhXz', + enableLocalEvaluation: true, + defaultFlagHandler: (str)=> { + return {enabled:false, isDefault:true, value:null} + } }); module.exports = () => { @@ -14,9 +18,10 @@ module.exports = () => { }); api.get('/:user', async (req, res) => { - const flags = await flagsmith.getIdentityFlags(req.params.user); + const flags = await flagsmith.getIdentityFlags(req.params.user, {checkout_v2: 1}); const fontSize = flags.getFeatureValue('font_size'); - res.json({ fontSize }); + const checkoutV2 = flags.isFeatureEnabled('checkout_v2'); + res.json({ fontSize, checkoutV2 }); }); return api; diff --git a/example/server/index.js b/example/server/index.js index 7e0014e..39e003f 100755 --- a/example/server/index.js +++ b/example/server/index.js @@ -12,17 +12,15 @@ app.server = http.createServer(app); app.use(bodyParser.json()); // api router -app.use('/', api()); +app.use('/api', api()); app.server.listen(PORT); console.log('Server started on port ' + app.server.address().port); console.log(); -console.log('Go to http://localhost:' + PORT + '/'); -console.log('To get an example feature state'); +console.log('Go to http://localhost:' + PORT + '/api'); +console.log('To get an example response for getFlags'); console.log(); -console.log('Go to http://localhost:' + PORT + '/flagsmith_sample_user'); +console.log('Go to http://localhost:' + PORT + '/api/flagsmith_sample_user'); console.log('To get an example feature state for a user'); -console.log('Go to http://localhost:' + PORT + '/flags'); -console.log('To get an example response for getFlags'); module.exports = app; diff --git a/sdk/index.ts b/sdk/index.ts index 952996d..d86bff3 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -33,17 +33,17 @@ export class Flagsmith { private analyticsProcessor?: AnalyticsProcessor; /** * A Flagsmith client. - * + * * Provides an interface for interacting with the Flagsmith http API. * Basic Usage:: - * + * * import flagsmith from Flagsmith * const flagsmith = new Flagsmith({environmentKey: ''}); * const environmentFlags = flagsmith.getEnvironmentFlags(); * const featureEnabled = environmentFlags.isFeatureEnabled('foo'); * const identityFlags = flagsmith.getIdentityFlags('identifier', {'foo': 'bar'}); * const featureEnabledForIdentity = identityFlags.isFeatureEnabled("foo") - * + * * @param {string} data.environmentKey: The environment key obtained from Flagsmith interface @param {string} data.apiUrl: Override the URL of the Flagsmith API to communicate with @param data.customHeaders: Additional headers to add to requests made to the @@ -120,7 +120,7 @@ export class Flagsmith { * Get all the flags for the current environment for a given identity. Will also upsert all traits to the Flagsmith API for future evaluations. Providing a trait with a value of None will remove the trait from the identity if it exists. - * + * * @param {string} identifier a unique identifier for the identity in the current environment, e.g. email address, username, uuid * @param {{[key:string]:any}} traits? a dictionary of traits to add / update on the identity in @@ -205,7 +205,13 @@ export class Flagsmith { ); } - const identityModel = this.buildIdentityModel(identifier, Object.values(traits)); + const identityModel = this.buildIdentityModel(identifier, Object.keys(traits).map((key)=>( + { + key, + value: traits[key] + } + ))); + const featureStates = getIdentityFeatureStates(this.environment, identityModel); return Flags.fromFeatureStateModels({ @@ -256,7 +262,7 @@ export class Flagsmith { } } - private buildIdentityModel(identifier: string, traits: any[]) { + private buildIdentityModel(identifier: string, traits: { key:string, value:any }[]) { if (!this.environment) { throw new FlagsmithClientError( 'Unable to build identity model when no local environment present.' diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts index 68dc142..697d64d 100644 --- a/sdk/polling_manager.ts +++ b/sdk/polling_manager.ts @@ -16,8 +16,9 @@ export class EnvironmentDataPollingManager { await this.main.update_environment(); }, this.refreshIntervalSeconds * 1000); }; - - this.interval = setTimeout(updateEnvironemnt, this.refreshIntervalSeconds * 1000); + // todo: this call should be awaited for getIdentityFlags/getEnvironmentFlags when enableLocalEvaluation is true + this.main.update_environment() + updateEnvironemnt() } stop() { From 89bc661e4374f1fddd6a451409c1cad47a97e561 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Mon, 14 Mar 2022 12:34:51 +0000 Subject: [PATCH 12/56] Throw on empty SDK key --- example/server/api/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/example/server/api/index.js b/example/server/api/index.js index 7a27002..317d3b8 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -1,8 +1,11 @@ const Router = require('express').Router; const { Flagsmith } = require('../../../build/sdk'); - +const environmentKey = "" +if(!environmentKey) { + throw new Error("Please generate a Server Side SDK Key in environment settings to run the example") +} const flagsmith = new Flagsmith({ - environmentKey: 'ser.dCxh8XoQc3Sw3JqMqMbhXz', + environmentKey, enableLocalEvaluation: true, defaultFlagHandler: (str)=> { return {enabled:false, isDefault:true, value:null} From 3eb2b1a31d220f3b748639c3ff550d84be54da0d Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Mon, 14 Mar 2022 12:36:24 +0000 Subject: [PATCH 13/56] Minor --- sdk/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/index.ts b/sdk/index.ts index d86bff3..f326e65 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -87,7 +87,6 @@ export class Flagsmith { this.identitiesUrl = `${this.apiUrl}identities/`; this.environmentUrl = `${this.apiUrl}environment-document/`; - this.environment; if (this.enableLocalEvaluation) { this.environmentDataPollingManager = new EnvironmentDataPollingManager( this, From cd487dbc92cc707f2ab10727efb8e7ce0f3e296c Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Mon, 14 Mar 2022 12:45:15 +0000 Subject: [PATCH 14/56] Update test, update updateEnvironment function names --- sdk/index.ts | 6 +++++- sdk/polling_manager.ts | 9 +++++---- tests/sdk/flagsmith.test.ts | 2 +- tests/sdk/polling.test.ts | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/sdk/index.ts b/sdk/index.ts index f326e65..e90395b 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -136,7 +136,11 @@ export class Flagsmith { return this.getIdentityFlagsFromApi(identifier, traits); } - async update_environment() { + /** + * Updates the environment state for local flag evaluation. + * You only need to call this if you wish to bypass environmentRefreshIntervalSeconds. + */ + async updateEnvironment() { this.environment = await this.getEnvironmentFromApi(); } diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts index 697d64d..a5be576 100644 --- a/sdk/polling_manager.ts +++ b/sdk/polling_manager.ts @@ -11,14 +11,15 @@ export class EnvironmentDataPollingManager { } start() { - const updateEnvironemnt = () => { + const updateEnvironment = () => { + if(this.interval) clearInterval(this.interval) this.interval = setInterval(async () => { - await this.main.update_environment(); + await this.main.updateEnvironment(); }, this.refreshIntervalSeconds * 1000); }; // todo: this call should be awaited for getIdentityFlags/getEnvironmentFlags when enableLocalEvaluation is true - this.main.update_environment() - updateEnvironemnt() + this.main.updateEnvironment() + updateEnvironment() } stop() { diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 437a167..300617c 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -25,7 +25,7 @@ test('test_update_environment_sets_environment', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); const flg = flagsmith(); - await flg.update_environment(); + await flg.updateEnvironment(); expect(flg.environment).toBeDefined(); // @ts-ignore diff --git a/tests/sdk/polling.test.ts b/tests/sdk/polling.test.ts index 9be49c9..6d604ff 100644 --- a/tests/sdk/polling.test.ts +++ b/tests/sdk/polling.test.ts @@ -18,7 +18,7 @@ test('test_polling_manager_calls_update_environment_on_start', async () => { pollingManager.start(); await delay(500); pollingManager.stop(); - expect(flagsmith.update_environment).toHaveBeenCalled(); + expect(flagsmith.updateEnvironment).toHaveBeenCalled(); }); test('test_polling_manager_calls_update_environment_on_each_refresh', async () => { @@ -30,5 +30,5 @@ test('test_polling_manager_calls_update_environment_on_each_refresh', async () = pollingManager.start(); await delay(450); pollingManager.stop(); - expect(flagsmith.update_environment).toHaveBeenCalledTimes(3); + expect(flagsmith.updateEnvironment).toHaveBeenCalledTimes(5); }); From dce0afcb474faf65b3a2044e2f9364f956fc8c90 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Mon, 14 Mar 2022 12:52:08 +0000 Subject: [PATCH 15/56] Log defaultFlagHandler on Feature does not exist error --- sdk/models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/models.ts b/sdk/models.ts index 51ab470..dd68b61 100644 --- a/sdk/models.ts +++ b/sdk/models.ts @@ -123,7 +123,7 @@ export class Flags { if (this.defaultFlagHandler) { return this.defaultFlagHandler(featureName); } - throw new FlagsmithClientError(`Feature does not exist: ${featureName}`); + throw new FlagsmithClientError(`Feature does not exist: ${featureName}, implement defaultFlagHandler to handle this case.`); } if (this.analyticsProcessor && flag.featureId) { From 9c4c1b4e27a0dcd55cc1d4797248e6930714ee40 Mon Sep 17 00:00:00 2001 From: Kyle Johnson Date: Tue, 15 Mar 2022 15:39:55 +0000 Subject: [PATCH 16/56] Update example package.json readme --- example/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/package.json b/example/package.json index 14e6fae..56a87ce 100644 --- a/example/package.json +++ b/example/package.json @@ -1,7 +1,7 @@ { - "name": "node-minimal", + "name": "flagsmith-nodejs-example", "version": "0.1.1", - "description": "Node Express Boilerplate", + "description": "An example using the flagsmith nodejs library", "main": "index.js", "scripts": { "start": "cd ../ && npm run build && cd ./example && node --inspect ./server", From eb474e6d02f82071727c8e6130bf4c00acea1717 Mon Sep 17 00:00:00 2001 From: Ben Rometsch Date: Tue, 15 Mar 2022 15:48:38 +0000 Subject: [PATCH 17/56] Renamed BT to Flagsmith last remnants --- package.json | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 32d8e83..ffb74a0 100644 --- a/package.json +++ b/package.json @@ -5,20 +5,21 @@ "main": "index.js", "repository": { "type": "git", - "url": "https://github.com/SolidStateGroup/bullet-train-nodejs-client" + "url": "https://github.com/Flagsmith/flagsmith-nodejs-client" }, "keywords": [ "nodejs", - "bullet train", "flagsmith", - "feature flagger", + "feature flags", + "feature toggles", + "remote configuration", "continuous deployment" ], "bugs": { - "url": "https://github.com/SolidStateGroup/bullet-train-nodejs-client/issues" + "url": "https://github.com/Flagsmith/flagsmith-nodejs-client/issues" }, - "homepage": "http://bullet-train.io", - "author": "SSG", + "homepage": "http://flagsmith.com/", + "author": "Flagsmith", "contributors": [ { "name": "Tom Stuart", @@ -26,7 +27,7 @@ }, { "name": "Kyle Johnson", - "email": "kyle@solidstategroup.com", + "email": "kyle.johnson@flagsmith.com", "url": "https://www.npmjs.com/~kyle-ssg" }, { From 3f54c4142ea348a8076ee52d93a885020bb15c61 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Tue, 15 Mar 2022 15:57:23 +0000 Subject: [PATCH 18/56] Use flagsmith 2.0.0-beta.1 in example --- example/package-lock.json | 1072 ++++++++++++++++++++++++++++++++++- example/package.json | 1 + example/server/api/index.js | 2 +- package-lock.json | 4 +- package.json | 4 +- 5 files changed, 1076 insertions(+), 7 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index 12f0331..b8d2430 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -1,8 +1,1003 @@ { - "name": "node-minimal", + "name": "flagsmith-nodejs-example", "version": "0.1.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "flagsmith-nodejs-example", + "version": "0.1.1", + "license": "MIT", + "dependencies": { + "flagsmith-nodejs": "^2.0.0-beta.1", + "node-cache": "^5.1.2", + "ssg-node-express": "4.16.4", + "ssg-util": "0.0.3" + }, + "engines": { + "node": "7.1.x", + "npm": "3.10.x" + } + }, + "node_modules/accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dependencies": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dependencies": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "engines": { + "node": "*" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "optional": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "dependencies": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-handlebars": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.0.tgz", + "integrity": "sha1-gKBwu4GbCeSvLKbQeA91zgXnXC8=", + "dependencies": { + "glob": "^6.0.4", + "graceful-fs": "^4.1.2", + "handlebars": "^4.0.5", + "object.assign": "^4.0.3", + "promise": "^7.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dependencies": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/express/node_modules/qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dependencies": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/raw-body/node_modules/depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/raw-body/node_modules/http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dependencies": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/raw-body/node_modules/setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "node_modules/express/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fetchify": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fetchify/-/fetchify-0.0.2.tgz", + "integrity": "sha1-v5JIOvSV0B5seHZ4E7lpUPW7Kms=" + }, + "node_modules/finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/flagsmith-nodejs": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/flagsmith-nodejs/-/flagsmith-nodejs-2.0.0-beta.1.tgz", + "integrity": "sha512-PZwLJJFvsLat+L2ovDNmJFbvSYs+HVKM0Ve6AkzTd6lqrhSTeqe2ZqWnjd7wvylx/fG6gv58sUMnV9gx07HNLg==", + "dependencies": { + "big-integer": "^1.6.51", + "md5": "^2.3.0", + "node-fetch": "^2.1.2", + "uuid": "^8.3.2" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz", + "integrity": "sha1-M3NSve1KC3FPPrhN6M6nZenTdgA=", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + }, + "node_modules/handlebars": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz", + "integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==", + "dependencies": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "dependencies": { + "mime-db": "~1.37.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "node_modules/moment": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dependencies": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "node_modules/parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dependencies": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssg-node-express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/ssg-node-express/-/ssg-node-express-4.16.4.tgz", + "integrity": "sha512-Hur6fup1phGAojSFZxhEsnv4aYPnARGCdg500cSXVmaJBu/rq2U3o7JyMDrvLX++hZfGx8bhv3mRR4gP4eivlA==", + "dependencies": { + "body-parser": "1.18.3", + "cors": "^2.8.3", + "express": "4.16.3", + "express-handlebars": "3.0.0", + "fetchify": "0.0.2", + "fs-extra": "2.0.0" + } + }, + "node_modules/ssg-util": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/ssg-util/-/ssg-util-0.0.3.tgz", + "integrity": "sha512-dxxyyv28vG67eLSAjsB4kszpk/s0wzesG0+3h8AracgpDgRIWPX+aF0oX0jo5oGzYJ7gCUzI68QnZK1HhGdgEA==", + "dependencies": { + "lodash": "4.17.11", + "moment": "2.23.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/uglify-js": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "optional": true, + "dependencies": { + "commander": "~2.17.1", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, "dependencies": { "accepts": { "version": "1.3.5", @@ -28,6 +1023,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" + }, "body-parser": { "version": "1.18.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", @@ -59,6 +1059,11 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -104,6 +1109,11 @@ "vary": "^1" } }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -293,6 +1303,17 @@ } } }, + "flagsmith-nodejs": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/flagsmith-nodejs/-/flagsmith-nodejs-2.0.0-beta.1.tgz", + "integrity": "sha512-PZwLJJFvsLat+L2ovDNmJFbvSYs+HVKM0Ve6AkzTd6lqrhSTeqe2ZqWnjd7wvylx/fG6gv58sUMnV9gx07HNLg==", + "requires": { + "big-integer": "^1.6.51", + "md5": "^2.3.0", + "node-fetch": "^2.1.2", + "uuid": "^8.3.2" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -388,6 +1409,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -401,6 +1427,16 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -475,6 +1511,14 @@ "clone": "2.x" } }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -659,6 +1703,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", @@ -688,11 +1737,30 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", diff --git a/example/package.json b/example/package.json index 56a87ce..24c73d2 100644 --- a/example/package.json +++ b/example/package.json @@ -15,6 +15,7 @@ "npm": "3.10.x" }, "dependencies": { + "flagsmith-nodejs": "^2.0.0-beta.1", "node-cache": "^5.1.2", "ssg-node-express": "4.16.4", "ssg-util": "0.0.3" diff --git a/example/server/api/index.js b/example/server/api/index.js index 317d3b8..e82cfa1 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -1,5 +1,5 @@ const Router = require('express').Router; -const { Flagsmith } = require('../../../build/sdk'); +const Flagsmith = require('flagsmith-nodejs').default; const environmentKey = "" if(!environmentKey) { throw new Error("Please generate a Server Side SDK Key in environment settings to run the example") diff --git a/package-lock.json b/package-lock.json index ad2b310..b501c4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "flagsmith-nodejs", - "version": "1.1.1", + "version": "2.0.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "flagsmith-nodejs", - "version": "1.1.1", + "version": "2.0.0-beta.1", "license": "MIT", "dependencies": { "big-integer": "^1.6.51", diff --git a/package.json b/package.json index 32d8e83..563c688 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "flagsmith-nodejs", - "version": "1.1.1", + "version": "2.0.0-beta.1", "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.", - "main": "index.js", + "main": "build/index.js", "repository": { "type": "git", "url": "https://github.com/SolidStateGroup/bullet-train-nodejs-client" From aebddc953edcb0c2fad6adebb6402d27a5b0c3dd Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 16 Mar 2022 14:03:47 +0200 Subject: [PATCH 19/56] chore: fixes as per PR comments --- example/server/api/index.js | 14 +++++---- flagsmith-engine/environments/models.ts | 16 +++++----- flagsmith-engine/features/models.ts | 14 ++++----- flagsmith-engine/identities/models.ts | 16 +++++----- flagsmith-engine/identities/util.ts | 2 +- flagsmith-engine/index.ts | 39 ++++++++++++------------ flagsmith-engine/organisations/models.ts | 12 ++++---- flagsmith-engine/projects/models.ts | 5 ++- flagsmith-engine/segments/evaluators.ts | 4 +-- flagsmith-engine/utils/errors.ts | 1 + flagsmith-engine/utils/hashing/index.ts | 23 ++++++-------- sdk/analytics.ts | 28 ----------------- sdk/index.ts | 27 +++++----------- sdk/models.ts | 4 ++- sdk/polling_manager.ts | 6 ++-- 15 files changed, 85 insertions(+), 126 deletions(-) create mode 100644 flagsmith-engine/utils/errors.ts diff --git a/example/server/api/index.js b/example/server/api/index.js index e82cfa1..17190f6 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -1,14 +1,16 @@ const Router = require('express').Router; const Flagsmith = require('flagsmith-nodejs').default; -const environmentKey = "" -if(!environmentKey) { - throw new Error("Please generate a Server Side SDK Key in environment settings to run the example") +const environmentKey = ''; +if (!environmentKey) { + throw new Error( + 'Please generate a Server Side SDK Key in environment settings to run the example' + ); } const flagsmith = new Flagsmith({ environmentKey, enableLocalEvaluation: true, - defaultFlagHandler: (str)=> { - return {enabled:false, isDefault:true, value:null} + defaultFlagHandler: str => { + return { enabled: false, isDefault: true, value: null }; } }); @@ -21,7 +23,7 @@ module.exports = () => { }); api.get('/:user', async (req, res) => { - const flags = await flagsmith.getIdentityFlags(req.params.user, {checkout_v2: 1}); + const flags = await flagsmith.getIdentityFlags(req.params.user, { checkout_v2: 1 }); const fontSize = flags.getFeatureValue('font_size'); const checkoutV2 = flags.isFeatureEnabled('checkout_v2'); res.json({ fontSize, checkoutV2 }); diff --git a/flagsmith-engine/environments/models.ts b/flagsmith-engine/environments/models.ts index 92a0e62..9b32716 100644 --- a/flagsmith-engine/environments/models.ts +++ b/flagsmith-engine/environments/models.ts @@ -14,17 +14,17 @@ export class EnvironmentAPIKeyModel { constructor( id: number, key: string, - created_at: number, + createdAt: number, name: string, - client_api_key: string, - expires_at?: number + clientApiKey: string, + expiresAt?: number ) { this.id = id; this.key = key; - this.createdAt = created_at; + this.createdAt = createdAt; this.name = name; - this.clientApiKey = client_api_key; - this.expiresAt = expires_at; + this.clientApiKey = clientApiKey; + this.expiresAt = expiresAt; } isValid() { @@ -42,9 +42,9 @@ export class EnvironmentModel { mixpanel_config?: IntegrationModel; heap_config?: IntegrationModel; - constructor(id: number, api_key: string, project: ProjectModel) { + constructor(id: number, apiKey: string, project: ProjectModel) { this.id = id; - this.apiKey = api_key; + this.apiKey = apiKey; this.project = project; } } diff --git a/flagsmith-engine/features/models.ts b/flagsmith-engine/features/models.ts index 3eb0a30..f12b305 100644 --- a/flagsmith-engine/features/models.ts +++ b/flagsmith-engine/features/models.ts @@ -51,7 +51,7 @@ export class FeatureStateModel { enabled: boolean; djangoID: number; featurestateUUID: string = uuidv4(); - _value: any; + private value: any; multivariateFeatureStateValues: MultivariateFeatureStateValueModel[] = []; constructor( @@ -59,24 +59,24 @@ export class FeatureStateModel { enabled: boolean, djangoID: number, value?: any, - featurestate_uuid: string = uuidv4() + featurestateUuid: string = uuidv4() ) { this.feature = feature; this.enabled = enabled; this.djangoID = djangoID; - this._value = value; - this.featurestateUUID = featurestate_uuid; + this.value = value; + this.featurestateUUID = featurestateUuid; } setValue(value: any) { - this._value = value; + this.value = value; } getValue(identityId?: number | string) { if (!!identityId && this.multivariateFeatureStateValues.length > 0) { return this.getMultivariateValue(identityId); } - return this._value; + return this.value; } get_feature_state_value() { @@ -100,6 +100,6 @@ export class FeatureStateModel { } startPercentage = limit; } - return this._value; + return this.value; } } diff --git a/flagsmith-engine/identities/models.ts b/flagsmith-engine/identities/models.ts index d448061..37dca06 100644 --- a/flagsmith-engine/identities/models.ts +++ b/flagsmith-engine/identities/models.ts @@ -15,17 +15,17 @@ export class IdentityModel { constructor( created_date: string, - identity_traits: TraitModel[], - identity_features: IdentityFeaturesList, - environment_api_key: string, + identityTraits: TraitModel[], + identityFeatures: IdentityFeaturesList, + environmentApiKey: string, identifier: string, - identity_uuid?: string + identityUuid?: string ) { - this.identityUuid = identity_uuid || uuidv4(); + this.identityUuid = identityUuid || uuidv4(); this.createdDate = Date.parse(created_date) || Date.now(); - this.identityTraits = identity_traits; - this.identityFeatures = new IdentityFeaturesList(...identity_features); - this.environmentApiKey = environment_api_key; + this.identityTraits = identityTraits; + this.identityFeatures = new IdentityFeaturesList(...identityFeatures); + this.environmentApiKey = environmentApiKey; this.identifier = identifier; } diff --git a/flagsmith-engine/identities/util.ts b/flagsmith-engine/identities/util.ts index 6973ced..c88e2e6 100644 --- a/flagsmith-engine/identities/util.ts +++ b/flagsmith-engine/identities/util.ts @@ -25,6 +25,6 @@ export function buildIdentityModel(identityJSON: any): IdentityModel { identityJSON.identity_uuid ); - model.djangoID = identityJSON['django_id']; + model.djangoID = identityJSON.django_id; return model; } diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index dbc93fd..58ebadb 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -4,56 +4,57 @@ import { IdentityModel } from './identities/models'; import { TraitModel } from './identities/traits/models'; import { getIdentitySegments } from './segments/evaluators'; import { SegmentModel } from './segments/models'; +import { FeatureStateNotFound } from './utils/errors'; function getIdentityFeatureStatesDict( environment: EnvironmentModel, identity: IdentityModel, - override_traits?: TraitModel[] + overrideTraits?: TraitModel[] ) { // Get feature states from the environment - const feature_states: { [key: number]: FeatureStateModel } = {}; + const featureStates: { [key: number]: FeatureStateModel } = {}; for (const fs of environment.featureStates) { - feature_states[fs.feature.id] = fs; + featureStates[fs.feature.id] = fs; } // Override with any feature states defined by matching segments - const identity_segments: SegmentModel[] = getIdentitySegments( + const identitySegments: SegmentModel[] = getIdentitySegments( environment, identity, - override_traits + overrideTraits ); - for (const matching_segment of identity_segments) { - for (const feature_state of matching_segment.featureStates) { + for (const matchingSegment of identitySegments) { + for (const featureState of matchingSegment.featureStates) { // note that feature states are stored on the segment in descending priority // order so we only care that the last one is added // TODO: can we optimise this? - feature_states[feature_state.feature.id] = feature_state; + featureStates[featureState.feature.id] = featureState; } } // Override with any feature states defined directly the identity for (const fs of identity.identityFeatures || []) { - if (feature_states[fs.feature.id]) { - feature_states[fs.feature.id] = fs; + if (featureStates[fs.feature.id]) { + featureStates[fs.feature.id] = fs; } } - return feature_states; + return featureStates; } export function getIdentityFeatureState( environment: EnvironmentModel, identity: IdentityModel, - feature_name: string, - override_traits?: TraitModel[] + featureName: string, + overrideTraits?: TraitModel[] ): FeatureStateModel { - const featureStates = getIdentityFeatureStatesDict(environment, identity, override_traits); + const featureStates = getIdentityFeatureStatesDict(environment, identity, overrideTraits); const matchingFeature = Object.values(featureStates).filter( - f => f.feature.name === feature_name + f => f.feature.name === featureName ); if (matchingFeature.length === 0) { - throw new Error('Feature State Not Found'); + throw new FeatureStateNotFound('Feature State Not Found'); } return matchingFeature[0]; @@ -64,14 +65,14 @@ export function getIdentityFeatureStates( identity: IdentityModel, overrideTraits?: TraitModel[] ): FeatureStateModel[] { - const feature_states = Object.values( + const featureStates = Object.values( getIdentityFeatureStatesDict(environment, identity, overrideTraits) ); if (environment.project.hideDisabledFlags) { - return feature_states.filter(fs => !!fs.enabled); + return featureStates.filter(fs => !!fs.enabled); } - return feature_states; + return featureStates; } export function getEnvironmentFeatureState(environment: EnvironmentModel, featureName: string) { diff --git a/flagsmith-engine/organisations/models.ts b/flagsmith-engine/organisations/models.ts index 8ee67f0..b532636 100644 --- a/flagsmith-engine/organisations/models.ts +++ b/flagsmith-engine/organisations/models.ts @@ -8,15 +8,15 @@ export class OrganisationModel { constructor( id: number, name: string, - feature_analytics: boolean, - stop_serving_flags: boolean, - persist_trait_data: boolean + featureAnalytics: boolean, + stopServingFlags: boolean, + persistTraitData: boolean ) { this.id = id; this.name = name; - this.featureAnalytics = feature_analytics; - this.stopServingFlags = stop_serving_flags; - this.persistTraitData = persist_trait_data; + this.featureAnalytics = featureAnalytics; + this.stopServingFlags = stopServingFlags; + this.persistTraitData = persistTraitData; } get unique_slug() { diff --git a/flagsmith-engine/projects/models.ts b/flagsmith-engine/projects/models.ts index a305c19..a7e9ddb 100644 --- a/flagsmith-engine/projects/models.ts +++ b/flagsmith-engine/projects/models.ts @@ -6,18 +6,17 @@ export class ProjectModel { name: string; organisation: OrganisationModel; hideDisabledFlags: boolean; - // FIXME segments: SegmentModel[] = []; constructor( id: number, name: string, - hide_disabled_flags: boolean, + hideDisabledFlags: boolean, organization: OrganisationModel ) { this.id = id; this.name = name; - this.hideDisabledFlags = hide_disabled_flags; + this.hideDisabledFlags = hideDisabledFlags; this.organisation = organization; } } diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index 54bd7d3..e8bb6cc 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -56,7 +56,7 @@ function traitsMatchSegmentRule( } function traitsMatchSegmentCondition( - identity_traits: TraitModel[], + identityTraits: TraitModel[], condition: SegmentConditionModel, segmentId: number | string, identityId: number | string @@ -65,7 +65,7 @@ function traitsMatchSegmentCondition( return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); } - const traits = identity_traits.filter(t => t.traitKey === condition.property_); + const traits = identityTraits.filter(t => t.traitKey === condition.property_); const trait = traits.length > 0 ? traits[0] : undefined; return trait ? condition.matchesTraitValue(trait.traitValue) : false; diff --git a/flagsmith-engine/utils/errors.ts b/flagsmith-engine/utils/errors.ts new file mode 100644 index 0000000..5b50f3a --- /dev/null +++ b/flagsmith-engine/utils/errors.ts @@ -0,0 +1 @@ +export class FeatureStateNotFound extends Error {} diff --git a/flagsmith-engine/utils/hashing/index.ts b/flagsmith-engine/utils/hashing/index.ts index c2da503..0d94de4 100644 --- a/flagsmith-engine/utils/hashing/index.ts +++ b/flagsmith-engine/utils/hashing/index.ts @@ -1,22 +1,10 @@ import md5 from 'md5'; import bigInt from 'big-integer'; -// def get_hashed_percentage_for_object_ids( -// object_ids: typing.Iterable[typing.Any], iterations: int = 1 -// ) -> float: -// """ -// Given a list of object ids, get a floating point number between 0 and 1 based on -// the hash of those ids. This should give the same value every time for any -// list of ids. - -// :param object_ids: list of object ids to calculate the has for -// :param iterations: num times to include each id in the generated string to hash -// :return: (float) number between 0 (inclusive) and 100 (exclusive) -// """ - const makeRepeated = (arr: Array, repeats: number) => Array.from({ length: repeats }, () => arr).flat(); +// https://stackoverflow.com/questions/12532871/how-to-convert-a-very-large-hex-number-to-decimal-in-javascript function h2d(s: any): string { function add(x: any, y: any) { var c = 0, @@ -42,7 +30,14 @@ function h2d(s: any): string { }); return dec; } - +/** + * Given a list of object ids, get a floating point number between 0 and 1 based on + * the hash of those ids. This should give the same value every time for any list of ids. + * + * @param {Array} objectIds list of object ids to calculate the has for + * @param {} iterations=1 num times to include each id in the generated string to hash + * @returns number number between 0 (inclusive) and 100 (exclusive) + */ export function getHashedPercentateForObjIds(objectIds: Array, iterations = 1): number { let to_hash = makeRepeated(objectIds, iterations).join(','); const hashedValue = md5(to_hash); diff --git a/sdk/analytics.ts b/sdk/analytics.ts index 9d406c5..7fb2a04 100644 --- a/sdk/analytics.ts +++ b/sdk/analytics.ts @@ -7,34 +7,6 @@ const ANALYTICS_TIMER = 10; const delay = (ms: number) => new Promise(resolve => setTimeout(() => resolve(undefined), ms)); -const retryFetch = ( - url: string, - fetchOptions = {}, - retries = 3, - retryDelay = 1000, - timeout: number -) => { - return new Promise((resolve, reject) => { - // check for timeout - if (timeout) setTimeout(() => reject('error: timeout'), timeout); - - const wrapper = (n: number) => { - fetch(url, fetchOptions) - .then(res => resolve(res)) - .catch(async err => { - if (n > 0) { - await delay(retryDelay); - wrapper(--n); - } else { - reject(err); - } - }); - }; - - wrapper(retries); - }); -}; - export class AnalyticsProcessor { private analyticsEndpoint: string; private environmentKey: string; diff --git a/sdk/index.ts b/sdk/index.ts index e90395b..d51d93c 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -29,7 +29,7 @@ export class Flagsmith { environmentUrl: string; environmentDataPollingManager?: EnvironmentDataPollingManager; - environment?: EnvironmentModel; + environment!: EnvironmentModel; private analyticsProcessor?: AnalyticsProcessor; /** * A Flagsmith client. @@ -188,12 +188,6 @@ export class Flagsmith { } private getEnvironmentFlagsFromDocument() { - if (!this.environment) { - throw new FlagsmithClientError( - 'Unable to build identity model when no local environment present.' - ); - } - return Flags.fromFeatureStateModels({ featureStates: getEnvironmentFeatureStates(this.environment), analyticsProcessor: this.analyticsProcessor, @@ -202,18 +196,13 @@ export class Flagsmith { } private getIdentityFlagsFromDocument(identifier: string, traits: { [key: string]: any }) { - if (!this.environment) { - throw new FlagsmithClientError( - 'Unable to build identity model when no local environment present.' - ); - } - - const identityModel = this.buildIdentityModel(identifier, Object.keys(traits).map((key)=>( - { + const identityModel = this.buildIdentityModel( + identifier, + Object.keys(traits).map(key => ({ key, value: traits[key] - } - ))); + })) + ); const featureStates = getIdentityFeatureStates(this.environment, identityModel); @@ -265,7 +254,7 @@ export class Flagsmith { } } - private buildIdentityModel(identifier: string, traits: { key:string, value:any }[]) { + private buildIdentityModel(identifier: string, traits: { key: string; value: any }[]) { if (!this.environment) { throw new FlagsmithClientError( 'Unable to build identity model when no local environment present.' @@ -275,8 +264,6 @@ export class Flagsmith { const traitModels = traits.map(trait => new TraitModel(trait.key, trait.value)); return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); } - - stop() {} } export default Flagsmith; diff --git a/sdk/models.ts b/sdk/models.ts index dd68b61..e8d59cb 100644 --- a/sdk/models.ts +++ b/sdk/models.ts @@ -123,7 +123,9 @@ export class Flags { if (this.defaultFlagHandler) { return this.defaultFlagHandler(featureName); } - throw new FlagsmithClientError(`Feature does not exist: ${featureName}, implement defaultFlagHandler to handle this case.`); + throw new FlagsmithClientError( + `Feature does not exist: ${featureName}, implement defaultFlagHandler to handle this case.` + ); } if (this.analyticsProcessor && flag.featureId) { diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts index a5be576..079879f 100644 --- a/sdk/polling_manager.ts +++ b/sdk/polling_manager.ts @@ -12,14 +12,14 @@ export class EnvironmentDataPollingManager { start() { const updateEnvironment = () => { - if(this.interval) clearInterval(this.interval) + if (this.interval) clearInterval(this.interval); this.interval = setInterval(async () => { await this.main.updateEnvironment(); }, this.refreshIntervalSeconds * 1000); }; // todo: this call should be awaited for getIdentityFlags/getEnvironmentFlags when enableLocalEvaluation is true - this.main.updateEnvironment() - updateEnvironment() + this.main.updateEnvironment(); + updateEnvironment(); } stop() { From 76f9d6c286c3cb2215a03472f2d4193e3da9d819 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 16 Mar 2022 14:17:36 +0200 Subject: [PATCH 20/56] chore: update exports for commonjs valid module --- sdk/index.ts | 5 +++-- sdk/polling_manager.ts | 2 +- tests/sdk/flagsmith.test.ts | 2 +- tests/sdk/polling.test.ts | 2 +- tests/sdk/utils.ts | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sdk/index.ts b/sdk/index.ts index d51d93c..b2eae0f 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -13,7 +13,7 @@ import { generateIdentitiesData, retryFetch } from './utils'; const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; -export class Flagsmith { +class Flagsmith { environmentKey?: string; apiUrl: string = DEFAULT_API_URL; customHeaders?: { [key: string]: any }; @@ -266,4 +266,5 @@ export class Flagsmith { } } -export default Flagsmith; +// export default Flagsmith; +export = Flagsmith; diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts index 079879f..6f7b34c 100644 --- a/sdk/polling_manager.ts +++ b/sdk/polling_manager.ts @@ -1,4 +1,4 @@ -import { Flagsmith } from '.'; +import Flagsmith from '.'; export class EnvironmentDataPollingManager { private interval?: NodeJS.Timer; diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 300617c..6cdd801 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -1,4 +1,4 @@ -import { Flagsmith } from '../../sdk'; +import Flagsmith from '../../sdk'; import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; import fetch, { Headers } from 'node-fetch'; import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils'; diff --git a/tests/sdk/polling.test.ts b/tests/sdk/polling.test.ts index 6d604ff..d0f7a3a 100644 --- a/tests/sdk/polling.test.ts +++ b/tests/sdk/polling.test.ts @@ -1,4 +1,4 @@ -import { Flagsmith } from '../../sdk'; +import Flagsmith from '../../sdk'; import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; import { delay } from '../../sdk/utils'; jest.mock('../../sdk'); diff --git a/tests/sdk/utils.ts b/tests/sdk/utils.ts index 8fe921d..7f2f892 100644 --- a/tests/sdk/utils.ts +++ b/tests/sdk/utils.ts @@ -1,7 +1,7 @@ import { readFileSync } from 'fs'; import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util'; import { AnalyticsProcessor } from '../../sdk/analytics'; -import { Flagsmith } from '../../sdk'; +import Flagsmith from '../../sdk'; const DATA_DIR = __dirname + '/data/'; From f722f1d4e19b0cbef5145ba8f39abab14783038f Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 17 Mar 2022 17:41:56 +0200 Subject: [PATCH 21/56] chore: fix exporting issues --- example/server/api/index.js | 2 +- index.ts | 5 ++++- sdk/index.ts | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/example/server/api/index.js b/example/server/api/index.js index 17190f6..cf66a04 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -1,5 +1,5 @@ const Router = require('express').Router; -const Flagsmith = require('flagsmith-nodejs').default; +const Flagsmith = require('../../../build'); const environmentKey = ''; if (!environmentKey) { throw new Error( diff --git a/index.ts b/index.ts index b25c6c5..1bd86d6 100644 --- a/index.ts +++ b/index.ts @@ -1,3 +1,6 @@ import Flagsmith from './sdk'; -export default Flagsmith; +export { Flagsmith } from './sdk'; +// export default Flagsmith; + +module.exports = Flagsmith; diff --git a/sdk/index.ts b/sdk/index.ts index b2eae0f..5c745d2 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -13,7 +13,7 @@ import { generateIdentitiesData, retryFetch } from './utils'; const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; -class Flagsmith { +export class Flagsmith { environmentKey?: string; apiUrl: string = DEFAULT_API_URL; customHeaders?: { [key: string]: any }; @@ -266,5 +266,5 @@ class Flagsmith { } } -// export default Flagsmith; -export = Flagsmith; +export default Flagsmith; +// export = Flagsmith; From 9b55819c790457e3c0b587b2f1452f70846551e7 Mon Sep 17 00:00:00 2001 From: Michael Beemer Date: Fri, 8 Apr 2022 13:18:22 -0400 Subject: [PATCH 22/56] Fix setTrait Return Type The `setTrait` method returns a promise but the interface makes it look like a synchronous operation. This could lead to race conditions if the call is not awaited before a `getValue` with a userId is executed. --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index eeac23b..9515fbc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -57,7 +57,7 @@ declare module 'flagsmith-nodejs' { userId: string, key: string, value: string | number | boolean - ): IUserIdentity; + ): Promise; interface IFeature { enabled: boolean; From 78b96e0352fb409af400b96ca7796c86ea16a277 Mon Sep 17 00:00:00 2001 From: Matthew Elwell Date: Tue, 12 Apr 2022 14:17:07 +0100 Subject: [PATCH 23/56] Fix traits logic --- sdk/index.ts | 2 +- sdk/utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/index.ts b/sdk/index.ts index 5c745d2..2e77cc7 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -149,7 +149,7 @@ export class Flagsmith { method: string, body?: { [key: string]: any } ): Promise { - const headers: { [key: string]: any } = {}; + const headers: { [key: string]: any } = {'Content-Type': 'application/json'}; if (this.environmentKey) { headers['X-Environment-Key'] = this.environmentKey as string; } diff --git a/sdk/utils.ts b/sdk/utils.ts index 259a229..8fe8670 100644 --- a/sdk/utils.ts +++ b/sdk/utils.ts @@ -3,7 +3,7 @@ import fetch, { Response } from 'node-fetch'; if (typeof fetch.default !== 'undefined') fetch = fetch.default; export function generateIdentitiesData(identifier: string, traits?: { [key: string]: any }) { - const traitsGenerated = Object.values(traits || {}).map(trait => ({ + const traitsGenerated = Object.entries(traits || {}).map(trait => ({ trait_key: trait[0], trait_value: trait[1] })); From 1c75677b9f137522db6f5b624dcf47bac5080c14 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 13 Apr 2022 18:45:14 +0100 Subject: [PATCH 24/56] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b2af027..86efa40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.2", "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.", "main": "build/index.js", "repository": { From 7d33644d3e1245fceb6db227b0abe0450c90bb4d Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Sat, 16 Apr 2022 11:15:17 +0100 Subject: [PATCH 25/56] Prevent local eval race conditions, getIdentitySegments, add server key check for local evaluation, update examples, improve tests --- example/server/api/index.js | 5 +++ example/server/index.js | 3 ++ package.json | 2 + sdk/index.ts | 69 ++++++++++++++++++++++++++++++--- tests/sdk/data/environment.json | 41 +++++++++++++++++++- tests/sdk/flagsmith.test.ts | 21 +++++++++- 6 files changed, 133 insertions(+), 8 deletions(-) diff --git a/example/server/api/index.js b/example/server/api/index.js index cf66a04..3ea3966 100644 --- a/example/server/api/index.js +++ b/example/server/api/index.js @@ -29,5 +29,10 @@ module.exports = () => { res.json({ fontSize, checkoutV2 }); }); + api.get('/:user/segments', async (req, res) => { + const segments = await flagsmith.getIdentitySegments(req.params.user, { checkout_v2: 1 }); + res.json(segments.map(v => v.name)); + }); + return api; }; diff --git a/example/server/index.js b/example/server/index.js index 39e003f..e92a557 100755 --- a/example/server/index.js +++ b/example/server/index.js @@ -22,5 +22,8 @@ console.log('To get an example response for getFlags'); console.log(); console.log('Go to http://localhost:' + PORT + '/api/flagsmith_sample_user'); console.log('To get an example feature state for a user'); +console.log(); +console.log('Go to http://localhost:' + PORT + '/api/flagsmith_sample_user/segments'); +console.log('To get the segments which the user belongs to'); module.exports = app; diff --git a/package.json b/package.json index 86efa40..c25d092 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,8 @@ "scripts": { "lint": "prettier --write .", "test": "jest --coverage --coverageReporters='text'", + "test:watch": "jest --coverage --watch --coverageReporters='text'", + "test:debug": "node --inspect-brk node_modules/.bin/jest --coverage --watch --coverageReporters='text'", "build": "tsc", "prepare": "husky install" }, diff --git a/sdk/index.ts b/sdk/index.ts index 2e77cc7..6bb9dcb 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -10,6 +10,8 @@ import { FlagsmithAPIError, FlagsmithClientError } from './errors'; import { DefaultFlag, Flags } from './models'; import { EnvironmentDataPollingManager } from './polling_manager'; import { generateIdentitiesData, retryFetch } from './utils'; +import { SegmentModel } from '../flagsmith-engine/segments/models'; +import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators'; const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; @@ -88,11 +90,17 @@ export class Flagsmith { this.environmentUrl = `${this.apiUrl}environment-document/`; if (this.enableLocalEvaluation) { + if (!this.environmentKey.startsWith('ser.')) { + console.error( + 'In order to use local evaluation, please generate a server key in the environment settings page.' + ); + } this.environmentDataPollingManager = new EnvironmentDataPollingManager( this, this.environmentRefreshIntervalSeconds ); this.environmentDataPollingManager.start(); + this.updateEnvironment(); } this.analyticsProcessor = data.enableAnalytics @@ -128,20 +136,67 @@ export class Flagsmith { */ getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { traits = traits || {}; - if (this.environment) { + if (this.enableLocalEvaluation) { return new Promise(resolve => - resolve(this.getIdentityFlagsFromDocument(identifier, traits || {})) + this.environmentPromise!.then(()=>{ + resolve(this.getIdentityFlagsFromDocument(identifier, traits || {})) + }) ); } return this.getIdentityFlagsFromApi(identifier, traits); } + /** + * Get the segments for the current environment for a given identity. Will also + upsert all traits to the Flagsmith API for future evaluations. Providing a + trait with a value of None will remove the trait from the identity if it exists. + * + * @param {string} identifier a unique identifier for the identity in the current + environment, e.g. email address, username, uuid + * @param {{[key:string]:any}} traits? a dictionary of traits to add / update on the identity in + Flagsmith, e.g. {"num_orders": 10} + * @returns Segments that the given identity belongs to. + */ + getIdentitySegments( + identifier: string, + traits?: { [key: string]: any } + ): Promise { + traits = traits || {}; + if (this.enableLocalEvaluation) { + return this.environmentPromise!.then(()=>{ + return new Promise(resolve => { + const identityModel = this.buildIdentityModel( + identifier, + Object.keys(traits || {}).map(key => ({ + key, + value: traits?.[key] + })) + ); + + const segments = getIdentitySegments(this.environment, identityModel); + return resolve(segments); + }); + }) + } + console.error('This function is only permitted with local evaluation.'); + return Promise.resolve([]); + } + /** * Updates the environment state for local flag evaluation. + * Sets a local promise to prevent race conditions in getIdentityFlags / getIdentitySegments. * You only need to call this if you wish to bypass environmentRefreshIntervalSeconds. */ async updateEnvironment() { - this.environment = await this.getEnvironmentFromApi(); + const request = this.getEnvironmentFromApi(); + if(!this.environmentPromise) { + this.environmentPromise = request.then((res)=>{ + this.environment = res; + }) + await this.environmentPromise + } else { + this.environment = await request; + } } private async getJSONResponse( @@ -149,7 +204,7 @@ export class Flagsmith { method: string, body?: { [key: string]: any } ): Promise { - const headers: { [key: string]: any } = {'Content-Type': 'application/json'}; + const headers: { [key: string]: any } = { 'Content-Type': 'application/json' }; if (this.environmentKey) { headers['X-Environment-Key'] = this.environmentKey as string; } @@ -182,6 +237,11 @@ export class Flagsmith { return data.json(); } + /** + * This promise ensures that the environment is retrieved before attempting to locally evaluate. + */ + private environmentPromise: Promise|undefined; + private async getEnvironmentFromApi() { const environment_data = await this.getJSONResponse(this.environmentUrl, 'GET'); return buildEnvironmentModel(environment_data); @@ -267,4 +327,3 @@ export class Flagsmith { } export default Flagsmith; -// export = Flagsmith; diff --git a/tests/sdk/data/environment.json b/tests/sdk/data/environment.json index d872ff1..aa991a2 100644 --- a/tests/sdk/data/environment.json +++ b/tests/sdk/data/environment.json @@ -11,7 +11,44 @@ }, "id": 1, "hide_disabled_flags": false, - "segments": [] + "segments": [ + { + "name": "regular_segment", + "feature_states": [ + { + "feature_state_value": "segment_override", + "multivariate_feature_state_values": [], + "django_id": 81027, + "feature": { + "name": "some_feature", + "type": "STANDARD", + "id": 1 + }, + "enabled": false + } + ], + "id": 1, + "rules": [ + { + "type": "ALL", + "conditions": [], + "rules": [ + { + "type": "ANY", + "conditions": [ + { + "value": "40", + "property_": "age", + "operator": "LESS_THAN" + } + ], + "rules": [] + } + ] + } + ] + } + ] }, "segment_overrides": [], "id": 1, @@ -30,4 +67,4 @@ "enabled": true } ] -} \ No newline at end of file +} diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 6cdd801..e91dccc 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -14,8 +14,10 @@ beforeEach(() => { }); test('test_flagsmith_starts_polling_manager_on_init_if_enabled', () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); new Flagsmith({ - environmentKey: 'key', + environmentKey: 'ser.key', enableLocalEvaluation: true }); expect(EnvironmentDataPollingManager).toBeCalled(); @@ -31,11 +33,28 @@ test('test_update_environment_sets_environment', async () => { // @ts-ignore flg.environment.featureStates[0].featurestateUUID = undefined; // @ts-ignore + flg.environment.project.segments[0].featureStates[0].featurestateUUID = undefined; + // @ts-ignore const model = environmentModel(JSON.parse(environmentJSON())); // @ts-ignore model.featureStates[0].featurestateUUID = undefined; + // @ts-ignore + model.project.segments[0].featureStates[0].featurestateUUID = undefined; expect(flg.environment).toStrictEqual(model); }); + +test('test_get_identity_segments', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + const flg = new Flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true + }); + const segments = await flg.getIdentitySegments("user", {age:21} ) + expect(segments[0].name).toEqual("regular_segment") + const segments2 = await flg.getIdentitySegments("user", {age:41} ) + expect(segments2.length).toEqual(0) +}); test('test_get_environment_flags_calls_api_when_no_local_environment', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); From ce8dde268249d3a8b56e0014ce2cc7389082d070 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Sat, 16 Apr 2022 11:17:25 +0100 Subject: [PATCH 26/56] lint --- sdk/index.ts | 18 +++++++++--------- tests/sdk/flagsmith.test.ts | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sdk/index.ts b/sdk/index.ts index 6bb9dcb..aaf36b7 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -138,8 +138,8 @@ export class Flagsmith { traits = traits || {}; if (this.enableLocalEvaluation) { return new Promise(resolve => - this.environmentPromise!.then(()=>{ - resolve(this.getIdentityFlagsFromDocument(identifier, traits || {})) + this.environmentPromise!.then(() => { + resolve(this.getIdentityFlagsFromDocument(identifier, traits || {})); }) ); } @@ -163,7 +163,7 @@ export class Flagsmith { ): Promise { traits = traits || {}; if (this.enableLocalEvaluation) { - return this.environmentPromise!.then(()=>{ + return this.environmentPromise!.then(() => { return new Promise(resolve => { const identityModel = this.buildIdentityModel( identifier, @@ -176,7 +176,7 @@ export class Flagsmith { const segments = getIdentitySegments(this.environment, identityModel); return resolve(segments); }); - }) + }); } console.error('This function is only permitted with local evaluation.'); return Promise.resolve([]); @@ -189,11 +189,11 @@ export class Flagsmith { */ async updateEnvironment() { const request = this.getEnvironmentFromApi(); - if(!this.environmentPromise) { - this.environmentPromise = request.then((res)=>{ + if (!this.environmentPromise) { + this.environmentPromise = request.then(res => { this.environment = res; - }) - await this.environmentPromise + }); + await this.environmentPromise; } else { this.environment = await request; } @@ -240,7 +240,7 @@ export class Flagsmith { /** * This promise ensures that the environment is retrieved before attempting to locally evaluate. */ - private environmentPromise: Promise|undefined; + private environmentPromise: Promise | undefined; private async getEnvironmentFromApi() { const environment_data = await this.getJSONResponse(this.environmentUrl, 'GET'); diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index e91dccc..1f3bb0d 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -50,10 +50,10 @@ test('test_get_identity_segments', async () => { environmentKey: 'ser.key', enableLocalEvaluation: true }); - const segments = await flg.getIdentitySegments("user", {age:21} ) - expect(segments[0].name).toEqual("regular_segment") - const segments2 = await flg.getIdentitySegments("user", {age:41} ) - expect(segments2.length).toEqual(0) + const segments = await flg.getIdentitySegments('user', { age: 21 }); + expect(segments[0].name).toEqual('regular_segment'); + const segments2 = await flg.getIdentitySegments('user', { age: 41 }); + expect(segments2.length).toEqual(0); }); test('test_get_environment_flags_calls_api_when_no_local_environment', async () => { // @ts-ignore From bf64da2c3623abce658c95dad7a0baf9c0c48e11 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 27 Apr 2022 15:30:08 +0100 Subject: [PATCH 27/56] Adjust default flag handling --- sdk/models.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/models.ts b/sdk/models.ts index e8d59cb..e9fda19 100644 --- a/sdk/models.ts +++ b/sdk/models.ts @@ -123,9 +123,9 @@ export class Flags { if (this.defaultFlagHandler) { return this.defaultFlagHandler(featureName); } - throw new FlagsmithClientError( - `Feature does not exist: ${featureName}, implement defaultFlagHandler to handle this case.` - ); + + return { enabled: false, isDefault: true, value: undefined }; + } if (this.analyticsProcessor && flag.featureId) { From a4a76c8d1eb90171a5b895953729e2349d601f54 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 27 Apr 2022 16:11:03 +0100 Subject: [PATCH 28/56] correct retries prop --- sdk/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/index.ts b/sdk/index.ts index aaf36b7..f078737 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -22,7 +22,7 @@ export class Flagsmith { requestTimeoutSeconds?: number; enableLocalEvaluation?: boolean = false; environmentRefreshIntervalSeconds: number = 60; - retries?: any; + retries?: number; enableAnalytics: boolean = false; defaultFlagHandler?: (featureName: string) => DefaultFlag; From 945192d436bde18c82f00d24745841d87e482591 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 27 Apr 2022 16:11:30 +0100 Subject: [PATCH 29/56] correct retries prop --- sdk/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/index.ts b/sdk/index.ts index f078737..7c527eb 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -70,7 +70,7 @@ export class Flagsmith { requestTimeoutSeconds?: number; enableLocalEvaluation?: boolean; environmentRefreshIntervalSeconds?: number; - retries?: any; + retries?: number; enableAnalytics?: boolean; defaultFlagHandler?: (featureName: string) => DefaultFlag; }) { From f95ad4c47024729e056945a969d09f99e7769e18 Mon Sep 17 00:00:00 2001 From: Ben Rometsch Date: Tue, 17 May 2022 13:26:22 +0100 Subject: [PATCH 30/56] added asdf --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9b72b16..f75e62e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ .idea/* node_modules/ -build/ \ No newline at end of file +build/ + +.tool-versions From 6a8a31deea39144e788a73db4e91f228d34843fa Mon Sep 17 00:00:00 2001 From: Ben Rometsch Date: Tue, 17 May 2022 13:33:59 +0100 Subject: [PATCH 31/56] Version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b501c4a..140a86e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.3", "license": "MIT", "dependencies": { "big-integer": "^1.6.51", diff --git a/package.json b/package.json index c25d092..a44f2cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.3", "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.", "main": "build/index.js", "repository": { From 187b9db33a5d22936fe2e6fa5a898f6e04a64f3b Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Tue, 17 May 2022 14:04:01 +0100 Subject: [PATCH 32/56] bump 2.0.0-beta.5, build on prepublish --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a44f2cc..608fd47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.3", + "version": "2.0.0-beta.5", "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.", "main": "build/index.js", "repository": { @@ -46,6 +46,7 @@ "test:watch": "jest --coverage --watch --coverageReporters='text'", "test:debug": "node --inspect-brk node_modules/.bin/jest --coverage --watch --coverageReporters='text'", "build": "tsc", + "prepublish": "npm run build", "prepare": "husky install" }, "dependencies": { From c8e16ce9d06df193e481cff5859ef9007ae77c1d Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 18 May 2022 10:46:12 +0100 Subject: [PATCH 33/56] ES5 support, beta.6 bump --- example/package-lock.json | 997 +------------------------------------- package.json | 2 +- tsconfig.json | 3 +- 3 files changed, 4 insertions(+), 998 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index b8d2430..beb17f7 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -1,1003 +1,8 @@ { "name": "flagsmith-nodejs-example", "version": "0.1.1", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "flagsmith-nodejs-example", - "version": "0.1.1", - "license": "MIT", - "dependencies": { - "flagsmith-nodejs": "^2.0.0-beta.1", - "node-cache": "^5.1.2", - "ssg-node-express": "4.16.4", - "ssg-util": "0.0.3" - }, - "engines": { - "node": "7.1.x", - "npm": "3.10.x" - } - }, - "node_modules/accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "dependencies": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", - "dependencies": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", - "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "engines": { - "node": "*" - } - }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "optional": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", - "dependencies": { - "accepts": "~1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", - "content-type": "~1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", - "qs": "6.5.1", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express-handlebars": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.0.tgz", - "integrity": "sha1-gKBwu4GbCeSvLKbQeA91zgXnXC8=", - "dependencies": { - "glob": "^6.0.4", - "graceful-fs": "^4.1.2", - "handlebars": "^4.0.5", - "object.assign": "^4.0.3", - "promise": "^7.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/express/node_modules/body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "dependencies": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", - "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/express/node_modules/qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "dependencies": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/raw-body/node_modules/depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/raw-body/node_modules/http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "dependencies": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/raw-body/node_modules/setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - }, - "node_modules/express/node_modules/statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fetchify": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fetchify/-/fetchify-0.0.2.tgz", - "integrity": "sha1-v5JIOvSV0B5seHZ4E7lpUPW7Kms=" - }, - "node_modules/finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/flagsmith-nodejs": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/flagsmith-nodejs/-/flagsmith-nodejs-2.0.0-beta.1.tgz", - "integrity": "sha512-PZwLJJFvsLat+L2ovDNmJFbvSYs+HVKM0Ve6AkzTd6lqrhSTeqe2ZqWnjd7wvylx/fG6gv58sUMnV9gx07HNLg==", - "dependencies": { - "big-integer": "^1.6.51", - "md5": "^2.3.0", - "node-fetch": "^2.1.2", - "uuid": "^8.3.2" - } - }, - "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz", - "integrity": "sha1-M3NSve1KC3FPPrhN6M6nZenTdgA=", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" - }, - "node_modules/handlebars": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz", - "integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==", - "dependencies": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ipaddr.js": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", - "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "node_modules/md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "bin": { - "mime": "cli.js" - } - }, - "node_modules/mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "dependencies": { - "mime-db": "~1.37.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" - }, - "node_modules/moment": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", - "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==", - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" - }, - "node_modules/node-cache": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", - "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", - "dependencies": { - "clone": "2.x" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "node_modules/parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dependencies": { - "asap": "~2.0.3" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", - "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", - "dependencies": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.8.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", - "dependencies": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssg-node-express": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/ssg-node-express/-/ssg-node-express-4.16.4.tgz", - "integrity": "sha512-Hur6fup1phGAojSFZxhEsnv4aYPnARGCdg500cSXVmaJBu/rq2U3o7JyMDrvLX++hZfGx8bhv3mRR4gP4eivlA==", - "dependencies": { - "body-parser": "1.18.3", - "cors": "^2.8.3", - "express": "4.16.3", - "express-handlebars": "3.0.0", - "fetchify": "0.0.2", - "fs-extra": "2.0.0" - } - }, - "node_modules/ssg-util": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/ssg-util/-/ssg-util-0.0.3.tgz", - "integrity": "sha512-dxxyyv28vG67eLSAjsB4kszpk/s0wzesG0+3h8AracgpDgRIWPX+aF0oX0jo5oGzYJ7gCUzI68QnZK1HhGdgEA==", - "dependencies": { - "lodash": "4.17.11", - "moment": "2.23.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", - "optional": true, - "dependencies": { - "commander": "~2.17.1", - "source-map": "~0.6.1" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - }, "dependencies": { "accepts": { "version": "1.3.5", diff --git a/package.json b/package.json index 608fd47..3761f20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.5", + "version": "2.0.0-beta.6", "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.", "main": "build/index.js", "repository": { diff --git a/tsconfig.json b/tsconfig.json index 777e51c..1fddca7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,8 @@ ], "compilerOptions": { "outDir": "./build", - "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "downlevelIteration": true, // Used to allow typescript to interpret Object.entries /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ From af72ca39b768dddc5e1c2037a86792dcbed759d9 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 18 May 2022 17:40:20 +0100 Subject: [PATCH 34/56] ES5 compat for IdentityFeaturesList --- flagsmith-engine/utils/collections.ts | 13 +------------ .../unit/identities/identities_models.test.ts | 11 ----------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/flagsmith-engine/utils/collections.ts b/flagsmith-engine/utils/collections.ts index 451ec14..cc8c688 100644 --- a/flagsmith-engine/utils/collections.ts +++ b/flagsmith-engine/utils/collections.ts @@ -1,14 +1,3 @@ import { FeatureStateModel } from '../features/models'; -export class IdentityFeaturesList extends Array { - public push(...e: FeatureStateModel[]): number { - for (const [_, item] of e.entries()) { - for (const [k, v] of this.entries()) { - if (v.djangoID === item.djangoID) { - throw new Error('feature state for this feature already exists'); - } - } - } - return super.push(...e); - } -} +export class IdentityFeaturesList extends Array {} diff --git a/tests/engine/unit/identities/identities_models.test.ts b/tests/engine/unit/identities/identities_models.test.ts index dcea7c5..f3d2ba1 100644 --- a/tests/engine/unit/identities/identities_models.test.ts +++ b/tests/engine/unit/identities/identities_models.test.ts @@ -92,14 +92,3 @@ test('test_append_feature_state', () => { expect(ident.identityFeatures).toContain(fs1); }); - -test('test_appending_feature_states_raises_duplicate_feature_state_if_fs_for_the_feature_already_exists', () => { - const ident = identityInSegment(); - - const fs1 = new FeatureStateModel(feature1(), false, 1); - const fs2 = new FeatureStateModel(feature1(), true, 1); - ident.identityFeatures.push(fs1); - expect(() => { - ident.identityFeatures.push(fs2); - }).toThrowError(); -}); From 571b5134f5a392a8b14602d186fd9de4937e5b03 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 18 May 2022 17:52:02 +0100 Subject: [PATCH 35/56] PR Feedback --- flagsmith-engine/features/models.ts | 4 ---- flagsmith-engine/identities/models.ts | 2 +- flagsmith-engine/index.ts | 2 +- flagsmith-engine/organisations/models.ts | 2 +- sdk/polling_manager.ts | 1 - tests/engine/unit/{egine.test.ts => engine.test.ts} | 0 tests/engine/unit/identities/identities_models.test.ts | 6 +++--- tests/engine/unit/organization/models.test.ts | 2 +- 8 files changed, 7 insertions(+), 12 deletions(-) rename tests/engine/unit/{egine.test.ts => engine.test.ts} (100%) diff --git a/flagsmith-engine/features/models.ts b/flagsmith-engine/features/models.ts index f12b305..69c000f 100644 --- a/flagsmith-engine/features/models.ts +++ b/flagsmith-engine/features/models.ts @@ -79,10 +79,6 @@ export class FeatureStateModel { return this.value; } - get_feature_state_value() { - return this.getValue(); - } - getMultivariateValue(identityID: number | string) { const percentageValue = getHashedPercentateForObjIds([ this.djangoID || this.featurestateUUID, diff --git a/flagsmith-engine/identities/models.ts b/flagsmith-engine/identities/models.ts index 37dca06..f841c12 100644 --- a/flagsmith-engine/identities/models.ts +++ b/flagsmith-engine/identities/models.ts @@ -37,7 +37,7 @@ export class IdentityModel { return `${env_key}_${identifier}`; } - update_traits(traits: TraitModel[]) { + updateTraits(traits: TraitModel[]) { const existingTraits: Map = new Map(); for (const trait of this.identityTraits) { existingTraits.set(trait.traitKey, trait); diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index 58ebadb..44e45e7 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -79,7 +79,7 @@ export function getEnvironmentFeatureState(environment: EnvironmentModel, featur const featuresStates = environment.featureStates.filter(f => f.feature.name === featureName); if (featuresStates.length === 0) { - throw new Error('Feature State Not Found'); + throw new FeatureStateNotFound('Feature State Not Found'); } return featuresStates[0]; diff --git a/flagsmith-engine/organisations/models.ts b/flagsmith-engine/organisations/models.ts index b532636..4e64912 100644 --- a/flagsmith-engine/organisations/models.ts +++ b/flagsmith-engine/organisations/models.ts @@ -19,7 +19,7 @@ export class OrganisationModel { this.persistTraitData = persistTraitData; } - get unique_slug() { + get uniqueSlug() { return this.id.toString() + '-' + this.name; } } diff --git a/sdk/polling_manager.ts b/sdk/polling_manager.ts index 6f7b34c..1fbf78c 100644 --- a/sdk/polling_manager.ts +++ b/sdk/polling_manager.ts @@ -17,7 +17,6 @@ export class EnvironmentDataPollingManager { await this.main.updateEnvironment(); }, this.refreshIntervalSeconds * 1000); }; - // todo: this call should be awaited for getIdentityFlags/getEnvironmentFlags when enableLocalEvaluation is true this.main.updateEnvironment(); updateEnvironment(); } diff --git a/tests/engine/unit/egine.test.ts b/tests/engine/unit/engine.test.ts similarity index 100% rename from tests/engine/unit/egine.test.ts rename to tests/engine/unit/engine.test.ts diff --git a/tests/engine/unit/identities/identities_models.test.ts b/tests/engine/unit/identities/identities_models.test.ts index f3d2ba1..ee85e42 100644 --- a/tests/engine/unit/identities/identities_models.test.ts +++ b/tests/engine/unit/identities/identities_models.test.ts @@ -54,7 +54,7 @@ test('test_update_traits_remove_traits_with_none_value', () => { const trait_key = ident.identityTraits[0].traitKey; const trait_to_remove = new TraitModel(trait_key, undefined); - ident.update_traits([trait_to_remove]); + ident.updateTraits([trait_to_remove]); expect(ident.identityTraits.length).toBe(0); }); @@ -66,7 +66,7 @@ test('test_update_identity_traits_updates_trait_value', () => { const traitValue = 'updated_trait_value'; const traitToUpdate = new TraitModel(traitKey, traitValue); - identity.update_traits([traitToUpdate]); + identity.updateTraits([traitToUpdate]); expect(identity.identityTraits.length).toBe(1); expect(identity.identityTraits[0]).toBe(traitToUpdate); @@ -77,7 +77,7 @@ test('test_update_traits_adds_new_traits', () => { const newTrait = new TraitModel('new_key', 'foobar'); - identity.update_traits([newTrait]); + identity.updateTraits([newTrait]); expect(identity.identityTraits.length).toBe(2); expect(identity.identityTraits).toContain(newTrait); diff --git a/tests/engine/unit/organization/models.test.ts b/tests/engine/unit/organization/models.test.ts index 1cb7ea4..b59d65f 100644 --- a/tests/engine/unit/organization/models.test.ts +++ b/tests/engine/unit/organization/models.test.ts @@ -8,5 +8,5 @@ test('Test builder', () => { stop_serving_flags: false, id: 13 }); - expect(model.unique_slug).toBe('13-Flagsmith'); + expect(model.uniqueSlug).toBe('13-Flagsmith'); }); From 605a26462f677da42692ad868a5991675285a082 Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Wed, 18 May 2022 18:21:47 +0100 Subject: [PATCH 36/56] Resolve todo on mv test --- tests/engine/unit/features/models.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/engine/unit/features/models.test.ts b/tests/engine/unit/features/models.test.ts index 2930269..2d01e96 100644 --- a/tests/engine/unit/features/models.test.ts +++ b/tests/engine/unit/features/models.test.ts @@ -65,8 +65,6 @@ test('test_feature_state_get_value_mv_values', () => { mvFeatureState.setValue(mvFeatureControlValue); - // TODO - // expect(mvFeatureState.getValue(3)).toBe(testCase[1]); - expect(1).toBe(1); + expect(mvFeatureState.getValue("test")).toBe(mvFeatureValue2); } }); From 5aca735b3656f23578d34e4162bc60a1e25806cc Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 18 May 2022 20:16:46 +0200 Subject: [PATCH 37/56] chore: update tests --- .gitmodules | 3 +++ flagsmith-engine/segments/models.ts | 2 -- flagsmith-engine/utils/hashing/index.ts | 4 ++-- tests/engine/unit/engine.test.ts | 20 +++++++++++++++++++ tests/engine/unit/features/models.test.ts | 6 ++++++ .../unit/segments/segments_model.test.ts | 3 ++- tests/engine_tests/engine-test-data | 1 + 7 files changed, 34 insertions(+), 5 deletions(-) create mode 160000 tests/engine_tests/engine-test-data diff --git a/.gitmodules b/.gitmodules index 426ec2c..b39e76a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "tests/engine/engine-tests/engine-test-data"] path = tests/engine/engine-tests/engine-test-data url = git@github.com:Flagsmith/engine-test-data.git +[submodule "tests/engine_tests/engine-test-data"] + path = tests/engine_tests/engine-test-data + url = git@github.com:Flagsmith/engine-test-data.git diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index 40ee5a4..8dc854e 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -23,8 +23,6 @@ export const matchingFunctions = { [CONDITION_OPERATORS.NOT_EQUAL]: (thisValue: any, otherValue: any) => thisValue != otherValue, [CONDITION_OPERATORS.CONTAINS]: (thisValue: any, otherValue: any) => otherValue.includes(thisValue), - [CONDITION_OPERATORS.NOT_CONTAINS]: (thisValue: any, otherValue: any) => - !otherValue.includes(thisValue) }; export class SegmentConditionModel { diff --git a/flagsmith-engine/utils/hashing/index.ts b/flagsmith-engine/utils/hashing/index.ts index 0d94de4..71e3220 100644 --- a/flagsmith-engine/utils/hashing/index.ts +++ b/flagsmith-engine/utils/hashing/index.ts @@ -39,8 +39,8 @@ function h2d(s: any): string { * @returns number number between 0 (inclusive) and 100 (exclusive) */ export function getHashedPercentateForObjIds(objectIds: Array, iterations = 1): number { - let to_hash = makeRepeated(objectIds, iterations).join(','); - const hashedValue = md5(to_hash); + let toHash = makeRepeated(objectIds, iterations).join(','); + const hashedValue = md5(toHash); const hashedInt = bigInt(h2d(hashedValue)); const value = (hashedInt.mod(9999).toJSNumber() / 9998) * 100; diff --git a/tests/engine/unit/engine.test.ts b/tests/engine/unit/engine.test.ts index d41447c..f19976d 100644 --- a/tests/engine/unit/engine.test.ts +++ b/tests/engine/unit/engine.test.ts @@ -25,6 +25,12 @@ test('test_identity_get_feature_state_without_any_override', () => { expect(feature_state.feature).toStrictEqual(feature1()); }); +test('test_identity_get_feature_state_without_any_override_no_fs', () => { + expect(() => { + getIdentityFeatureState(environment(), identity(), 'nonExistentName'); + }).toThrowError('Feature State Not Found'); +}); + test('test_identity_get_all_feature_states_no_segments', () => { const env = environment(); const ident = identity(); @@ -61,6 +67,20 @@ test('test_identity_get_all_feature_states_with_traits', () => { expect(featureStates[0].getValue()).toBe('segment_override'); }); +test('test_identity_get_all_feature_states_with_traits_hideDisabledFlags', () => { + const trait_models = new TraitModel(segmentConditionProperty, segmentConditionStringValue); + + const env = environmentWithSegmentOverride(); + env.project.hideDisabledFlags = true; + + const featureStates = getIdentityFeatureStates( + env, + identityInSegment(), + [trait_models] + ); + expect(featureStates.length).toBe(0); +}); + test('test_environment_get_all_feature_states', () => { const env = environment(); const featureStates = getEnvironmentFeatureStates(env); diff --git a/tests/engine/unit/features/models.test.ts b/tests/engine/unit/features/models.test.ts index 2930269..58f7ec0 100644 --- a/tests/engine/unit/features/models.test.ts +++ b/tests/engine/unit/features/models.test.ts @@ -7,6 +7,12 @@ import { } from '../../../../flagsmith-engine/features/models'; import { feature1 } from '../utils'; +test('test_compare_feature_model', () => { + const fm1 = new FeatureModel(1, 'a', 'test'); + const fm2 = new FeatureModel(1, 'a', 'test'); + expect(fm1.eq(fm2)).toBe(true); +}); + test('test_initializing_feature_state_creates_default_feature_state_uuid', () => { const featureState = new FeatureStateModel(feature1(), true, 1); expect(featureState.featurestateUUID).toBeDefined(); diff --git a/tests/engine/unit/segments/segments_model.test.ts b/tests/engine/unit/segments/segments_model.test.ts index 00c48a7..a9e00d5 100644 --- a/tests/engine/unit/segments/segments_model.test.ts +++ b/tests/engine/unit/segments/segments_model.test.ts @@ -61,7 +61,8 @@ const conditionMatchCases: [string, string | number | boolean, string, boolean][ [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'bar', false], [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'baz', true], [CONDITION_OPERATORS.REGEX, 'foo', '[a-z]+', true], - [CONDITION_OPERATORS.REGEX, 'FOO', '[a-z]+', false] + [CONDITION_OPERATORS.REGEX, 'FOO', '[a-z]+', false], + ['BAD_OP', 'a', 'a', false] ]; test('test_segment_condition_matches_trait_value', () => { diff --git a/tests/engine_tests/engine-test-data b/tests/engine_tests/engine-test-data new file mode 160000 index 0000000..d4c595f --- /dev/null +++ b/tests/engine_tests/engine-test-data @@ -0,0 +1 @@ +Subproject commit d4c595f86d75ef9340e678a5e447d8d68f9a7aaa From 298ab468da43418e520838d0e5c3abbefd8b33b9 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 18 May 2022 20:47:38 +0200 Subject: [PATCH 38/56] chore: remove redundant submodule --- .gitmodules | 3 --- tests/engine_tests/engine-test-data | 1 - 2 files changed, 4 deletions(-) delete mode 160000 tests/engine_tests/engine-test-data diff --git a/.gitmodules b/.gitmodules index b39e76a..426ec2c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "tests/engine/engine-tests/engine-test-data"] path = tests/engine/engine-tests/engine-test-data url = git@github.com:Flagsmith/engine-test-data.git -[submodule "tests/engine_tests/engine-test-data"] - path = tests/engine_tests/engine-test-data - url = git@github.com:Flagsmith/engine-test-data.git diff --git a/tests/engine_tests/engine-test-data b/tests/engine_tests/engine-test-data deleted file mode 160000 index d4c595f..0000000 --- a/tests/engine_tests/engine-test-data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d4c595f86d75ef9340e678a5e447d8d68f9a7aaa From 707fbd9baf0e7a088ff17a9da2e33c7edca480b6 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 10:22:14 +0200 Subject: [PATCH 39/56] chore: remove submodule files --- README.md | 7 + package-lock.json | 4 +- tests/engine/engine-tests/engine-test-data | 1 + .../engine-tests/engine-test-data/.gitignore | 1 - .../environment_n9fbf9h3v4fFgH3U3ngWhb.json | 12393 ---------------- .../engine-tests/engine-test-data/readme.md | 30 - 6 files changed, 10 insertions(+), 12426 deletions(-) create mode 160000 tests/engine/engine-tests/engine-test-data delete mode 100644 tests/engine/engine-tests/engine-test-data/.gitignore delete mode 100644 tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json delete mode 100644 tests/engine/engine-tests/engine-test-data/readme.md diff --git a/README.md b/README.md index 63f0a48..b4497c2 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,13 @@ Please read [CONTRIBUTING.md](https://gist.github.com/kyle-ssg/c36a03aebe492e45c If you encounter a bug or feature request we would like to hear about it. Before you submit an issue please search existing issues in order to prevent duplicates. +## Testing + +To run the local tests you need to run following command beforehand: +``` +git submodule add git@github.com:Flagsmith/engine-test-data.git tests/engine/engine-tests/engine-test-data/ +``` + ## Get in touch If you have any questions about our projects you can email support@flagsmith.com. diff --git a/package-lock.json b/package-lock.json index 140a86e..79c7eb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.3", + "version": "2.0.0-beta.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.3", + "version": "2.0.0-beta.6", "license": "MIT", "dependencies": { "big-integer": "^1.6.51", diff --git a/tests/engine/engine-tests/engine-test-data b/tests/engine/engine-tests/engine-test-data new file mode 160000 index 0000000..d4c595f --- /dev/null +++ b/tests/engine/engine-tests/engine-test-data @@ -0,0 +1 @@ +Subproject commit d4c595f86d75ef9340e678a5e447d8d68f9a7aaa diff --git a/tests/engine/engine-tests/engine-test-data/.gitignore b/tests/engine/engine-tests/engine-test-data/.gitignore deleted file mode 100644 index 723ef36..0000000 --- a/tests/engine/engine-tests/engine-test-data/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.idea \ No newline at end of file diff --git a/tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json b/tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json deleted file mode 100644 index de53092..0000000 --- a/tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json +++ /dev/null @@ -1,12393 +0,0 @@ -{ - "environment": { - "project": { - "hide_disabled_flags": false, - "segments": [ - { - "name": "regular_segment", - "feature_states": [ - { - "feature_state_value": "segment_override", - "multivariate_feature_state_values": [], - "django_id": 81027, - "feature": { - "id": 15058, - "type": "STANDARD", - "name": "string_feature" - }, - "enabled": false - } - ], - "id": 4267, - "rules": [ - { - "type": "ALL", - "conditions": [], - "rules": [ - { - "type": "ANY", - "conditions": [ - { - "value": "40", - "property_": "age", - "operator": "LESS_THAN" - } - ], - "rules": [] - }, - { - "type": "ANY", - "conditions": [ - { - "value": "21", - "property_": "age", - "operator": "GREATER_THAN_INCLUSIVE" - } - ], - "rules": [] - }, - { - "type": "ANY", - "conditions": [ - { - "value": "green", - "property_": "favourite_colour", - "operator": "EQUAL" - }, - { - "value": "blue", - "property_": "favourite_colour", - "operator": "EQUAL" - } - ], - "rules": [] - } - ] - } - ] - }, - { - "name": "10_percent", - "feature_states": [ - { - "feature_state_value": "", - "multivariate_feature_state_values": [], - "django_id": 81026, - "feature": { - "id": 15060, - "type": "STANDARD", - "name": "basic_flag" - }, - "enabled": true - } - ], - "id": 4268, - "rules": [ - { - "type": "ALL", - "conditions": [], - "rules": [ - { - "type": "ANY", - "conditions": [ - { - "value": "0.1", - "property_": "", - "operator": "PERCENTAGE_SPLIT" - } - ], - "rules": [] - } - ] - } - ] - } - ], - "name": "Edge API Test Project", - "id": 5359, - "organisation": { - "persist_trait_data": true, - "name": "Flagsmith", - "feature_analytics": false, - "stop_serving_flags": false, - "id": 13 - } - }, - "api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "feature_states": [ - { - "feature_state_value": "foo", - "multivariate_feature_state_values": [], - "django_id": 78978, - "feature": { - "id": 15058, - "type": "STANDARD", - "name": "string_feature" - }, - "enabled": true - }, - { - "feature_state_value": 1234, - "multivariate_feature_state_values": [], - "django_id": 78980, - "feature": { - "id": 15059, - "type": "STANDARD", - "name": "integer_feature" - }, - "enabled": true - }, - { - "feature_state_value": null, - "multivariate_feature_state_values": [], - "django_id": 78982, - "feature": { - "id": 15060, - "type": "STANDARD", - "name": "basic_flag" - }, - "enabled": false - }, - { - "feature_state_value": "12.34", - "multivariate_feature_state_values": [], - "django_id": 78984, - "feature": { - "id": 15061, - "type": "STANDARD", - "name": "float_feature" - }, - "enabled": true - }, - { - "feature_state_value": "foo", - "multivariate_feature_state_values": [ - { - "id": 3404, - "multivariate_feature_option": { - "value": "baz" - }, - "percentage_allocation": 30.0 - }, - { - "id": 3402, - "multivariate_feature_option": { - "value": "bar" - }, - "percentage_allocation": 30.0 - } - ], - "django_id": 78986, - "feature": { - "id": 15062, - "type": "MULTIVARIATE", - "name": "mv_feature" - }, - "enabled": true - } - ], - "id": 12561 - }, - "identities_and_responses": [ - { - "identity": { - "identity_uuid": "10f435fb-66fa-4e5e-9787-75729a4e8372", - "identifier": "54463d93-392f-493a-90b5-a1d3afe60f4b", - "created_date": "2021-12-15T14:40:00.880997", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_54463d93-392f-493a-90b5-a1d3afe60f4b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 49 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32102998 - }, - "response": { - "traits": [ - { - "id": 26678015, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678016, - "trait_key": "age", - "trait_value": 49 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "275b5d01-6ffb-4183-9c4e-b031a4b4af56", - "identifier": "7765d342-16c5-4c1c-a461-459d39f65b85", - "created_date": "2021-12-15T14:40:00.881011", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7765d342-16c5-4c1c-a461-459d39f65b85", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 93 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103670 - }, - "response": { - "traits": [ - { - "id": 26678279, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678280, - "trait_key": "age", - "trait_value": 93 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "baebd517-e00e-4d53-843d-8e3db194c6aa", - "identifier": "ce99d7bb-2fbd-4fb3-8c4d-0f4a11c5a9aa", - "created_date": "2021-12-15T14:40:00.881018", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_ce99d7bb-2fbd-4fb3-8c4d-0f4a11c5a9aa", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 56 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103671 - }, - "response": { - "traits": [ - { - "id": 26678281, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678282, - "trait_key": "age", - "trait_value": 56 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "6e707eed-851d-487c-996b-4fc207c8b95d", - "identifier": "7fb675cf-91fc-439e-8e5f-896bbaa46319", - "created_date": "2021-12-15T14:40:00.881024", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7fb675cf-91fc-439e-8e5f-896bbaa46319", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 71 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103674 - }, - "response": { - "traits": [ - { - "id": 26678283, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678284, - "trait_key": "age", - "trait_value": 71 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "8e3fe9c7-5ec7-4547-a4d1-6b90a0b25cd4", - "identifier": "f0ca10b8-7088-4336-ae8c-5332e91f1554", - "created_date": "2021-12-15T14:40:00.881031", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_f0ca10b8-7088-4336-ae8c-5332e91f1554", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 88 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103676 - }, - "response": { - "traits": [ - { - "id": 26678285, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678286, - "trait_key": "age", - "trait_value": 88 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "dfb7b7ec-510c-4367-8a00-a5692cb53fb9", - "identifier": "ef981b6d-22d8-4daa-ab2d-f3f26db80a86", - "created_date": "2021-12-15T14:40:00.881037", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_ef981b6d-22d8-4daa-ab2d-f3f26db80a86", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 84 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103677 - }, - "response": { - "traits": [ - { - "id": 26678287, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678288, - "trait_key": "age", - "trait_value": 84 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "639b6c09-c52d-4b57-ab5a-aac5d0b5a3f7", - "identifier": "a2f85378-ea82-44c0-8998-be477402379c", - "created_date": "2021-12-15T14:40:00.881045", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_a2f85378-ea82-44c0-8998-be477402379c", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 78 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103679 - }, - "response": { - "traits": [ - { - "id": 26678290, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678291, - "trait_key": "age", - "trait_value": 78 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "a1862f60-16f4-4658-b495-f05c6ff3c6f5", - "identifier": "64ebc978-1f6a-4c22-8f5b-8b0f83478ef1", - "created_date": "2021-12-15T14:40:00.881051", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_64ebc978-1f6a-4c22-8f5b-8b0f83478ef1", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 85 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103681 - }, - "response": { - "traits": [ - { - "id": 26678292, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678293, - "trait_key": "age", - "trait_value": 85 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "0133a745-c508-436c-b142-6fb214e6984a", - "identifier": "2db1db6a-2dab-4416-8510-b2a99db4f05a", - "created_date": "2021-12-15T14:40:00.881058", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2db1db6a-2dab-4416-8510-b2a99db4f05a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 60 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103682 - }, - "response": { - "traits": [ - { - "id": 26678294, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678295, - "trait_key": "age", - "trait_value": 60 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "fd9ebd93-4acb-4402-b923-92f74dda62fa", - "identifier": "9f7d2eb7-e01c-4bec-9738-5eaeaa6bf776", - "created_date": "2021-12-15T14:40:00.881064", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_9f7d2eb7-e01c-4bec-9738-5eaeaa6bf776", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 51 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103683 - }, - "response": { - "traits": [ - { - "id": 26678296, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678297, - "trait_key": "age", - "trait_value": 51 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "8e619996-500f-430e-b234-3cf8c7f83161", - "identifier": "e5af06dd-d3a1-4f53-9185-8989b6eaa848", - "created_date": "2021-12-15T14:40:00.881070", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_e5af06dd-d3a1-4f53-9185-8989b6eaa848", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 6 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103684 - }, - "response": { - "traits": [ - { - "id": 26678298, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678299, - "trait_key": "age", - "trait_value": 6 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "f22be96e-d364-4017-8929-7771446a861e", - "identifier": "81b634c1-fde0-4d32-af2b-2ddd08d5dee6", - "created_date": "2021-12-15T14:40:00.881076", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_81b634c1-fde0-4d32-af2b-2ddd08d5dee6", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 66 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103685 - }, - "response": { - "traits": [ - { - "id": 26678300, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678301, - "trait_key": "age", - "trait_value": 66 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "601bb6b9-8e55-4b3c-8709-9f047dc30711", - "identifier": "dbcc4f61-44c2-4117-a5fd-16237b66f46d", - "created_date": "2021-12-15T14:40:00.881082", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_dbcc4f61-44c2-4117-a5fd-16237b66f46d", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 35 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103686 - }, - "response": { - "traits": [ - { - "id": 26678302, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678303, - "trait_key": "age", - "trait_value": 35 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "fa5753f0-3e0e-4b4b-9386-a8ed5fb60322", - "identifier": "388b793f-5843-46c9-af6b-a942b52527b2", - "created_date": "2021-12-15T14:40:00.881088", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_388b793f-5843-46c9-af6b-a942b52527b2", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 30 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103688 - }, - "response": { - "traits": [ - { - "id": 26678304, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678305, - "trait_key": "age", - "trait_value": 30 - } - ], - "flags": [ - { - "id": 81027, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "segment_override", - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": 9893 - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "bd2749dd-4026-4d79-83c3-3882df2643f8", - "identifier": "3719f827-9c23-4956-b82a-7c2f5102479f", - "created_date": "2021-12-15T14:40:00.881095", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3719f827-9c23-4956-b82a-7c2f5102479f", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 77 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103689 - }, - "response": { - "traits": [ - { - "id": 26678306, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678307, - "trait_key": "age", - "trait_value": 77 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "448ee1bf-6417-4688-a2a2-d2172773a94a", - "identifier": "db0436cb-ede2-42e4-b2d5-65af13e0852a", - "created_date": "2021-12-15T14:40:00.881100", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_db0436cb-ede2-42e4-b2d5-65af13e0852a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 48 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103690 - }, - "response": { - "traits": [ - { - "id": 26678308, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678309, - "trait_key": "age", - "trait_value": 48 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "8b4a3afc-4d75-456c-b6d2-542170cd068b", - "identifier": "397cd01d-c6a1-451c-8795-4c9686c22a3b", - "created_date": "2021-12-15T14:40:00.881106", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_397cd01d-c6a1-451c-8795-4c9686c22a3b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 86 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103692 - }, - "response": { - "traits": [ - { - "id": 26678310, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678311, - "trait_key": "age", - "trait_value": 86 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "871d212c-6b59-4c23-b3e3-e7a695ebc3c9", - "identifier": "32fd6b46-69d0-4123-8e35-ca4401e8bc3e", - "created_date": "2021-12-15T14:40:00.881112", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_32fd6b46-69d0-4123-8e35-ca4401e8bc3e", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 63 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103693 - }, - "response": { - "traits": [ - { - "id": 26678312, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678313, - "trait_key": "age", - "trait_value": 63 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "b428ae53-8688-452e-ad9d-450ed99aa4b1", - "identifier": "31f5d2d7-3736-478c-a887-e77c16cc8dfd", - "created_date": "2021-12-15T14:40:00.881118", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_31f5d2d7-3736-478c-a887-e77c16cc8dfd", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 37 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103695 - }, - "response": { - "traits": [ - { - "id": 26678314, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678315, - "trait_key": "age", - "trait_value": 37 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "82fd8c76-9943-454d-9c35-1f68af410aea", - "identifier": "15ef44aa-34b5-4366-a201-c80e33d9f169", - "created_date": "2021-12-15T14:40:00.881124", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_15ef44aa-34b5-4366-a201-c80e33d9f169", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 32 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103696 - }, - "response": { - "traits": [ - { - "id": 26678316, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678317, - "trait_key": "age", - "trait_value": 32 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "6e04dd89-0028-4f2c-b87f-17e71e414085", - "identifier": "2d6d8b94-504c-437e-afd2-c84cc4e72b8b", - "created_date": "2021-12-15T14:40:00.881130", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2d6d8b94-504c-437e-afd2-c84cc4e72b8b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 83 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103699 - }, - "response": { - "traits": [ - { - "id": 26678318, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678319, - "trait_key": "age", - "trait_value": 83 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c49440f9-1b03-464b-8d98-4cdd7bd8480d", - "identifier": "20e6204b-e396-4d4b-a861-bb136c276ac2", - "created_date": "2021-12-15T14:40:00.881135", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_20e6204b-e396-4d4b-a861-bb136c276ac2", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 68 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103700 - }, - "response": { - "traits": [ - { - "id": 26678320, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678321, - "trait_key": "age", - "trait_value": 68 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "575cac45-a94d-4b91-ae86-10f692c30aa2", - "identifier": "c8159d13-3b99-4355-84df-c8e541d55384", - "created_date": "2021-12-15T14:40:00.881142", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c8159d13-3b99-4355-84df-c8e541d55384", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 76 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103702 - }, - "response": { - "traits": [ - { - "id": 26678322, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678323, - "trait_key": "age", - "trait_value": 76 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "fd29ee25-7b53-4947-8910-a7e261ae9ef7", - "identifier": "42c798b6-1a36-4cf3-8df0-b6347020323a", - "created_date": "2021-12-15T14:40:00.881148", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_42c798b6-1a36-4cf3-8df0-b6347020323a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 62 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103703 - }, - "response": { - "traits": [ - { - "id": 26678324, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678325, - "trait_key": "age", - "trait_value": 62 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "491088a0-337c-4ebb-a6f0-d116ebaf5d0f", - "identifier": "170effbe-4388-49a5-9872-700688b628b9", - "created_date": "2021-12-15T14:40:00.881153", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_170effbe-4388-49a5-9872-700688b628b9", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 69 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103704 - }, - "response": { - "traits": [ - { - "id": 26678326, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678327, - "trait_key": "age", - "trait_value": 69 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "aa5a77b1-241d-4af4-a580-370d85965f03", - "identifier": "042b3a46-4575-419a-8a2f-62baa3226668", - "created_date": "2021-12-15T14:40:00.881161", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_042b3a46-4575-419a-8a2f-62baa3226668", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 20 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103705 - }, - "response": { - "traits": [ - { - "id": 26678328, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678329, - "trait_key": "age", - "trait_value": 20 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "40cdc7cd-765b-4f71-8b1e-7fa723116201", - "identifier": "83295382-6d39-4db1-ac66-1ebb6e98b70e", - "created_date": "2021-12-15T14:40:00.881167", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_83295382-6d39-4db1-ac66-1ebb6e98b70e", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 91 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103706 - }, - "response": { - "traits": [ - { - "id": 26678330, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678331, - "trait_key": "age", - "trait_value": 91 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c136ba1f-1bdb-43d3-af72-c1a7e33677de", - "identifier": "3debf4d7-3aff-4a8e-98fe-35d3add7f9fb", - "created_date": "2021-12-15T14:40:00.881173", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3debf4d7-3aff-4a8e-98fe-35d3add7f9fb", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 92 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103707 - }, - "response": { - "traits": [ - { - "id": 26678332, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678333, - "trait_key": "age", - "trait_value": 92 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "b349658d-8aac-4fc7-bd64-c48a4d143c14", - "identifier": "fc300e2a-b1b8-4408-8830-676e47abaf2c", - "created_date": "2021-12-15T14:40:00.881178", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_fc300e2a-b1b8-4408-8830-676e47abaf2c", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 34 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103708 - }, - "response": { - "traits": [ - { - "id": 26678334, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678335, - "trait_key": "age", - "trait_value": 34 - } - ], - "flags": [ - { - "id": 81027, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "segment_override", - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": 9893 - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "24e4d0fa-6ea5-4773-8abb-44f79048d2a9", - "identifier": "56a8c68b-5015-47dd-97ee-0d727eb16266", - "created_date": "2021-12-15T14:40:00.881184", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_56a8c68b-5015-47dd-97ee-0d727eb16266", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 78 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103709 - }, - "response": { - "traits": [ - { - "id": 26678336, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678337, - "trait_key": "age", - "trait_value": 78 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "5de2cf7f-93f4-4d08-8aa3-381d9b1e3d42", - "identifier": "8e660bf8-cffa-46e3-878a-111627965710", - "created_date": "2021-12-15T14:40:00.881190", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_8e660bf8-cffa-46e3-878a-111627965710", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 44 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103710 - }, - "response": { - "traits": [ - { - "id": 26678338, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678339, - "trait_key": "age", - "trait_value": 44 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "febef74c-1a54-4ca6-83c5-e205a8b570e2", - "identifier": "269c4565-50fa-4e4d-9d1b-e349545c9b1b", - "created_date": "2021-12-15T14:40:00.881196", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_269c4565-50fa-4e4d-9d1b-e349545c9b1b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 56 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103712 - }, - "response": { - "traits": [ - { - "id": 26678340, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678341, - "trait_key": "age", - "trait_value": 56 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "5077957d-8af4-4400-835d-8859017d4f19", - "identifier": "fe0b7a97-f9f9-4ec9-b1d8-142939493321", - "created_date": "2021-12-15T14:40:00.881202", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_fe0b7a97-f9f9-4ec9-b1d8-142939493321", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 56 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103714 - }, - "response": { - "traits": [ - { - "id": 26678342, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678343, - "trait_key": "age", - "trait_value": 56 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "6b06b383-bef7-40b6-9eb6-c94868b4e8f1", - "identifier": "efb574f7-091b-45fa-800d-ebec477efb51", - "created_date": "2021-12-15T14:40:00.881208", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_efb574f7-091b-45fa-800d-ebec477efb51", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 29 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103715 - }, - "response": { - "traits": [ - { - "id": 26678344, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678345, - "trait_key": "age", - "trait_value": 29 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "24ef7912-df97-4c1a-98d4-c9b3c0c294a0", - "identifier": "82cd7c27-6ae9-471e-9b8a-d9829383b489", - "created_date": "2021-12-15T14:40:00.881214", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_82cd7c27-6ae9-471e-9b8a-d9829383b489", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 52 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103716 - }, - "response": { - "traits": [ - { - "id": 26678346, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678347, - "trait_key": "age", - "trait_value": 52 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "77566c33-28ab-4e89-9eb0-782fc26aebeb", - "identifier": "727ae8b6-f421-453c-9310-408150fbe28c", - "created_date": "2021-12-15T14:40:00.881220", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_727ae8b6-f421-453c-9310-408150fbe28c", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 66 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103718 - }, - "response": { - "traits": [ - { - "id": 26678348, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678349, - "trait_key": "age", - "trait_value": 66 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "d27a61ad-300f-4f4c-b88f-d9c8b4eabdce", - "identifier": "b3305fe0-77ac-4a1b-995e-94c413c686d0", - "created_date": "2021-12-15T14:40:00.881226", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b3305fe0-77ac-4a1b-995e-94c413c686d0", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 24 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103719 - }, - "response": { - "traits": [ - { - "id": 26678350, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678351, - "trait_key": "age", - "trait_value": 24 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "e3331902-c64e-49df-a1fc-a07226991f0c", - "identifier": "c99e2bda-f55d-4964-bdd2-80ecfd00297d", - "created_date": "2021-12-15T14:40:00.881232", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c99e2bda-f55d-4964-bdd2-80ecfd00297d", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 75 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103722 - }, - "response": { - "traits": [ - { - "id": 26678352, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678353, - "trait_key": "age", - "trait_value": 75 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "fa599660-3914-465b-b2f4-b363fa9cd3c2", - "identifier": "67476160-7c89-4d5c-bc1a-22ef4a8b2168", - "created_date": "2021-12-15T14:40:00.881238", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_67476160-7c89-4d5c-bc1a-22ef4a8b2168", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 88 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103724 - }, - "response": { - "traits": [ - { - "id": 26678354, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678355, - "trait_key": "age", - "trait_value": 88 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "dcffa2e6-c6d5-41c0-a7d4-5123dd6f6f0e", - "identifier": "b1cc98db-4e99-4f2c-a364-ef6382864188", - "created_date": "2021-12-15T14:40:00.881244", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b1cc98db-4e99-4f2c-a364-ef6382864188", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 12 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103725 - }, - "response": { - "traits": [ - { - "id": 26678356, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678357, - "trait_key": "age", - "trait_value": 12 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "70fdb139-3a53-46ae-8da3-ad0a3ab62313", - "identifier": "11586d45-02f1-48ac-b640-741447251909", - "created_date": "2021-12-15T14:40:00.881249", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_11586d45-02f1-48ac-b640-741447251909", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 22 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103727 - }, - "response": { - "traits": [ - { - "id": 26678359, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678360, - "trait_key": "age", - "trait_value": 22 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "032abbac-93de-4ae0-b2ef-41695bc28fa7", - "identifier": "9515c224-5adc-4e44-bc39-21942779c323", - "created_date": "2021-12-15T14:40:00.881255", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_9515c224-5adc-4e44-bc39-21942779c323", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 83 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103728 - }, - "response": { - "traits": [ - { - "id": 26678363, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678364, - "trait_key": "age", - "trait_value": 83 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "2f85e99a-8685-4ec3-896a-64cf36872c35", - "identifier": "dc6b85e3-e03b-4019-8b6d-97b1d7d25492", - "created_date": "2021-12-15T14:40:00.881261", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_dc6b85e3-e03b-4019-8b6d-97b1d7d25492", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 47 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103730 - }, - "response": { - "traits": [ - { - "id": 26678365, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678366, - "trait_key": "age", - "trait_value": 47 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "3da8f9a1-c795-4d66-babf-39f22432556e", - "identifier": "70f674c4-0474-46aa-ac39-0d7a373fafca", - "created_date": "2021-12-15T14:40:00.881267", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_70f674c4-0474-46aa-ac39-0d7a373fafca", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 62 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103731 - }, - "response": { - "traits": [ - { - "id": 26678367, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678368, - "trait_key": "age", - "trait_value": 62 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "dbb45f9e-a894-4acd-8127-fe0a370468be", - "identifier": "85457200-feeb-468a-91ac-e6397254429a", - "created_date": "2021-12-15T14:40:00.881273", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_85457200-feeb-468a-91ac-e6397254429a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 60 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103733 - }, - "response": { - "traits": [ - { - "id": 26678369, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678370, - "trait_key": "age", - "trait_value": 60 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c04d3ee7-1044-4d88-8deb-8e6ad4020d1b", - "identifier": "46e87d76-34ca-410d-ac4c-67400770c398", - "created_date": "2021-12-15T14:40:00.881279", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_46e87d76-34ca-410d-ac4c-67400770c398", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 64 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103735 - }, - "response": { - "traits": [ - { - "id": 26678371, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678372, - "trait_key": "age", - "trait_value": 64 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "f9590820-76bb-4979-8ee8-cb31a1c800af", - "identifier": "ff74f26a-e832-465b-a165-375b1f70905a", - "created_date": "2021-12-15T14:40:00.881287", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_ff74f26a-e832-465b-a165-375b1f70905a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 33 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103737 - }, - "response": { - "traits": [ - { - "id": 26678374, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678375, - "trait_key": "age", - "trait_value": 33 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "5c7e29fa-e380-48e6-b721-f7b47a329966", - "identifier": "c2ff801e-e145-411d-ba68-9dd2b9871bfe", - "created_date": "2021-12-15T14:40:00.881293", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c2ff801e-e145-411d-ba68-9dd2b9871bfe", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 97 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103738 - }, - "response": { - "traits": [ - { - "id": 26678376, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678377, - "trait_key": "age", - "trait_value": 97 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "5b945288-e15b-43a1-880f-c93ff6f4cffb", - "identifier": "5fd8e83e-bd87-42e7-8c2a-fd31960feb72", - "created_date": "2021-12-15T14:40:00.881299", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_5fd8e83e-bd87-42e7-8c2a-fd31960feb72", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 8 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103739 - }, - "response": { - "traits": [ - { - "id": 26678378, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678379, - "trait_key": "age", - "trait_value": 8 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "380a4595-2d3d-4d3c-aecd-861a4ff1b05f", - "identifier": "2dbbc953-31b3-4bf4-9f63-a09bd37baf78", - "created_date": "2021-12-15T14:40:00.881304", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2dbbc953-31b3-4bf4-9f63-a09bd37baf78", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 85 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103741 - }, - "response": { - "traits": [ - { - "id": 26678380, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678381, - "trait_key": "age", - "trait_value": 85 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "3006cc06-24d3-4819-8722-e6e994c6878d", - "identifier": "2af98d3d-be2f-4bee-b7ae-83c53e1b2811", - "created_date": "2021-12-15T14:40:00.881310", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2af98d3d-be2f-4bee-b7ae-83c53e1b2811", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 7 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103743 - }, - "response": { - "traits": [ - { - "id": 26678382, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678383, - "trait_key": "age", - "trait_value": 7 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "e40de32b-bf2b-4ed4-b5a4-a5883a30adb6", - "identifier": "b21bd1e2-bb87-4135-aca7-e30f465de632", - "created_date": "2021-12-15T14:40:00.881316", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b21bd1e2-bb87-4135-aca7-e30f465de632", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 72 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103744 - }, - "response": { - "traits": [ - { - "id": 26678384, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678385, - "trait_key": "age", - "trait_value": 72 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "10c294e0-06b2-47b8-96c9-842a9d19410e", - "identifier": "96fbbd8f-b5f4-4267-a2db-9f6848dcb20a", - "created_date": "2021-12-15T14:40:00.881322", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_96fbbd8f-b5f4-4267-a2db-9f6848dcb20a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 72 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103746 - }, - "response": { - "traits": [ - { - "id": 26678386, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678387, - "trait_key": "age", - "trait_value": 72 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c5f06308-bf71-4f47-bcd1-baee81e9f0db", - "identifier": "b8f06d73-0430-438d-b788-d91851449908", - "created_date": "2021-12-15T14:40:00.881328", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_b8f06d73-0430-438d-b788-d91851449908", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 33 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103747 - }, - "response": { - "traits": [ - { - "id": 26678388, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678389, - "trait_key": "age", - "trait_value": 33 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "1d48c04d-879e-4554-a0bf-c50638ea7945", - "identifier": "430f2a5c-dc93-497f-be0c-859687126d95", - "created_date": "2021-12-15T14:40:00.881334", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_430f2a5c-dc93-497f-be0c-859687126d95", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 97 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103748 - }, - "response": { - "traits": [ - { - "id": 26678390, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678391, - "trait_key": "age", - "trait_value": 97 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "3c9392ec-4c55-45e9-a8ee-60f6e1cd053f", - "identifier": "c3483e1f-ac4e-4e1e-b398-bedde811f441", - "created_date": "2021-12-15T14:40:00.881339", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c3483e1f-ac4e-4e1e-b398-bedde811f441", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 98 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103750 - }, - "response": { - "traits": [ - { - "id": 26678392, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678393, - "trait_key": "age", - "trait_value": 98 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "264fd0b7-d2ac-499b-8cb2-d5e321f28fea", - "identifier": "65e8ea3f-6f3f-4eee-8ad5-30c7a7c7bfe4", - "created_date": "2021-12-15T14:40:00.881345", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_65e8ea3f-6f3f-4eee-8ad5-30c7a7c7bfe4", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 16 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103754 - }, - "response": { - "traits": [ - { - "id": 26678394, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678395, - "trait_key": "age", - "trait_value": 16 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c3adcad5-cee3-4c9b-a1bd-204767c426ac", - "identifier": "cbaa7fae-9453-448a-bff1-d571be7c8a6b", - "created_date": "2021-12-15T14:40:00.881351", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_cbaa7fae-9453-448a-bff1-d571be7c8a6b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 76 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103757 - }, - "response": { - "traits": [ - { - "id": 26678396, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678397, - "trait_key": "age", - "trait_value": 76 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "1e4962d0-8dbe-48cf-a5a2-f91a3329d665", - "identifier": "3ecde417-838e-4469-90a9-d7e925200b51", - "created_date": "2021-12-15T14:40:00.881357", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3ecde417-838e-4469-90a9-d7e925200b51", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 46 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103760 - }, - "response": { - "traits": [ - { - "id": 26678398, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678399, - "trait_key": "age", - "trait_value": 46 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c9e9802c-1bfc-478e-8a13-48f4db8c4780", - "identifier": "555bb037-cc46-47de-b0fa-4bcab906f5e7", - "created_date": "2021-12-15T14:40:00.881362", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_555bb037-cc46-47de-b0fa-4bcab906f5e7", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 97 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103761 - }, - "response": { - "traits": [ - { - "id": 26678400, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678401, - "trait_key": "age", - "trait_value": 97 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "814cc5e7-d6e6-4cab-9f0d-2e023816bd2e", - "identifier": "57fd428e-b41c-4e5f-b47d-de9faed376e3", - "created_date": "2021-12-15T14:40:00.881368", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_57fd428e-b41c-4e5f-b47d-de9faed376e3", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 80 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103763 - }, - "response": { - "traits": [ - { - "id": 26678402, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678403, - "trait_key": "age", - "trait_value": 80 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "a56babd1-7c0d-4f29-ad0f-99905bc993a4", - "identifier": "933949d7-b731-4f3a-a2dc-3d83d0beb1ea", - "created_date": "2021-12-15T14:40:00.881374", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_933949d7-b731-4f3a-a2dc-3d83d0beb1ea", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 88 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103764 - }, - "response": { - "traits": [ - { - "id": 26678404, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678405, - "trait_key": "age", - "trait_value": 88 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "65571c7a-ff3c-45f9-9760-ba25d7460e9c", - "identifier": "a78cf315-d2d8-4d04-b075-e9aba7421706", - "created_date": "2021-12-15T14:40:00.881380", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_a78cf315-d2d8-4d04-b075-e9aba7421706", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 68 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103768 - }, - "response": { - "traits": [ - { - "id": 26678406, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678407, - "trait_key": "age", - "trait_value": 68 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "ad2cb625-4d07-4af6-9eba-18a7b3841fe8", - "identifier": "0d0eb3b4-aab5-4a2e-b82a-47e84c57c64d", - "created_date": "2021-12-15T14:40:00.881386", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_0d0eb3b4-aab5-4a2e-b82a-47e84c57c64d", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 28 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103770 - }, - "response": { - "traits": [ - { - "id": 26678408, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678409, - "trait_key": "age", - "trait_value": 28 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "4a9bb0c3-78e3-42ba-9389-c9d7e60606af", - "identifier": "7edcfe01-784c-4951-8c22-5f84f0569381", - "created_date": "2021-12-15T14:40:00.881392", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7edcfe01-784c-4951-8c22-5f84f0569381", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 47 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103775 - }, - "response": { - "traits": [ - { - "id": 26678410, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678411, - "trait_key": "age", - "trait_value": 47 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "d7f49884-6c09-4072-879e-2739e819b93a", - "identifier": "c334969d-25bd-4ea2-9cd3-634fecdc542d", - "created_date": "2021-12-15T14:40:00.881398", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_c334969d-25bd-4ea2-9cd3-634fecdc542d", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 50 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103778 - }, - "response": { - "traits": [ - { - "id": 26678412, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678413, - "trait_key": "age", - "trait_value": 50 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "e518ad76-3358-41cc-a754-fa94ef3a9326", - "identifier": "28501e08-e978-4336-9ddd-d90d87983ab3", - "created_date": "2021-12-15T14:40:00.881404", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_28501e08-e978-4336-9ddd-d90d87983ab3", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 43 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103779 - }, - "response": { - "traits": [ - { - "id": 26678414, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678415, - "trait_key": "age", - "trait_value": 43 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "72cba3cd-0d49-4ba2-988e-cdbcda0190a8", - "identifier": "1b33fc3f-3c0e-480c-acce-1937779c743b", - "created_date": "2021-12-15T14:40:00.881410", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_1b33fc3f-3c0e-480c-acce-1937779c743b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 4 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103782 - }, - "response": { - "traits": [ - { - "id": 26678416, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678417, - "trait_key": "age", - "trait_value": 4 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "9deeec31-7e48-4916-a788-2690f7bb6a67", - "identifier": "2269ea5c-4509-4b7e-acd8-1f7763837464", - "created_date": "2021-12-15T14:40:00.881417", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2269ea5c-4509-4b7e-acd8-1f7763837464", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 14 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103784 - }, - "response": { - "traits": [ - { - "id": 26678418, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678419, - "trait_key": "age", - "trait_value": 14 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "07d47ed2-dc53-4966-b3f4-c1f2646cdf1d", - "identifier": "a4bc3ba0-7366-4bf2-b309-37baf2d0f45f", - "created_date": "2021-12-15T14:40:00.881423", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_a4bc3ba0-7366-4bf2-b309-37baf2d0f45f", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 62 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103786 - }, - "response": { - "traits": [ - { - "id": 26678420, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678421, - "trait_key": "age", - "trait_value": 62 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "ae780a18-9c46-4791-b455-6c33ac560257", - "identifier": "1969664e-a236-46e7-91af-84dca50a313b", - "created_date": "2021-12-15T14:40:00.881428", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_1969664e-a236-46e7-91af-84dca50a313b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 43 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103787 - }, - "response": { - "traits": [ - { - "id": 26678422, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678423, - "trait_key": "age", - "trait_value": 43 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "5756015d-720f-485d-8816-027de60a7680", - "identifier": "7137c59d-0bc0-43d2-b1ad-492b0a03aa85", - "created_date": "2021-12-15T14:40:00.881434", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_7137c59d-0bc0-43d2-b1ad-492b0a03aa85", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 52 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103790 - }, - "response": { - "traits": [ - { - "id": 26678427, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678428, - "trait_key": "age", - "trait_value": 52 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "a2137b00-8448-44bd-9c57-ef894cdcc974", - "identifier": "f8fe67d7-958e-452c-a4d4-8249c8b9369c", - "created_date": "2021-12-15T14:40:00.881440", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_f8fe67d7-958e-452c-a4d4-8249c8b9369c", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 67 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103791 - }, - "response": { - "traits": [ - { - "id": 26678429, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678430, - "trait_key": "age", - "trait_value": 67 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "9a6fd956-9984-4584-8071-6a4d801cbd7b", - "identifier": "d2a57b07-3ee1-4b0a-8cd9-e572d14635ce", - "created_date": "2021-12-15T14:40:00.881445", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d2a57b07-3ee1-4b0a-8cd9-e572d14635ce", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 90 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103792 - }, - "response": { - "traits": [ - { - "id": 26678431, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678432, - "trait_key": "age", - "trait_value": 90 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "f921a860-788b-4a5d-8074-e683b924cf0d", - "identifier": "65190952-1717-454b-bef2-b38ea62837c7", - "created_date": "2021-12-15T14:40:00.881450", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_65190952-1717-454b-bef2-b38ea62837c7", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 64 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103794 - }, - "response": { - "traits": [ - { - "id": 26678433, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678434, - "trait_key": "age", - "trait_value": 64 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "a71ee7df-89a6-48be-8307-231361e5010e", - "identifier": "fb098dba-4be6-4117-b95a-fd930c1598b0", - "created_date": "2021-12-15T14:40:00.881456", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_fb098dba-4be6-4117-b95a-fd930c1598b0", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 65 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103796 - }, - "response": { - "traits": [ - { - "id": 26678435, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678436, - "trait_key": "age", - "trait_value": 65 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "69d09c74-b19a-442a-8061-c7b0641b5642", - "identifier": "3e06036d-fa99-4b46-a843-9bd5b1cdf171", - "created_date": "2021-12-15T14:40:00.881462", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_3e06036d-fa99-4b46-a843-9bd5b1cdf171", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 51 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103797 - }, - "response": { - "traits": [ - { - "id": 26678437, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678438, - "trait_key": "age", - "trait_value": 51 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "f3b604bb-63f5-4b9f-bf41-b6584e7cccac", - "identifier": "29f66219-8344-4df4-a294-92efb44db0c5", - "created_date": "2021-12-15T14:40:00.881467", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_29f66219-8344-4df4-a294-92efb44db0c5", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 97 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103798 - }, - "response": { - "traits": [ - { - "id": 26678439, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678440, - "trait_key": "age", - "trait_value": 97 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "f7c290ed-649a-4ac6-9832-1f415baac78d", - "identifier": "1ccf1600-ca87-47f0-8cd9-225f9f8389a6", - "created_date": "2021-12-15T14:40:00.881473", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_1ccf1600-ca87-47f0-8cd9-225f9f8389a6", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 76 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103799 - }, - "response": { - "traits": [ - { - "id": 26678441, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678442, - "trait_key": "age", - "trait_value": 76 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "98ed8afd-e03d-4706-9443-55650ebc146a", - "identifier": "4f5a88b9-2b1b-4c0a-9f9f-a3fbeda05dfb", - "created_date": "2021-12-15T14:40:00.881479", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_4f5a88b9-2b1b-4c0a-9f9f-a3fbeda05dfb", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 68 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103800 - }, - "response": { - "traits": [ - { - "id": 26678443, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678444, - "trait_key": "age", - "trait_value": 68 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "89174521-10de-480f-a330-7051d1fbf30a", - "identifier": "742956df-236e-4cc9-8b55-634a7b1da4af", - "created_date": "2021-12-15T14:40:00.881505", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_742956df-236e-4cc9-8b55-634a7b1da4af", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 37 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103802 - }, - "response": { - "traits": [ - { - "id": 26678445, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678446, - "trait_key": "age", - "trait_value": 37 - } - ], - "flags": [ - { - "id": 81027, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "segment_override", - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": 9893 - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "bee25dd0-765b-4451-85aa-977a0294b3d1", - "identifier": "923649a9-5850-4227-a965-32d34ebf9769", - "created_date": "2021-12-15T14:40:00.881511", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_923649a9-5850-4227-a965-32d34ebf9769", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 4 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103803 - }, - "response": { - "traits": [ - { - "id": 26678447, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678448, - "trait_key": "age", - "trait_value": 4 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "e95c0f65-6338-445d-9a5e-31cc10ed072c", - "identifier": "233de9e2-df63-49ca-9f5a-dca000db568d", - "created_date": "2021-12-15T14:40:00.881517", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_233de9e2-df63-49ca-9f5a-dca000db568d", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 19 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103804 - }, - "response": { - "traits": [ - { - "id": 26678449, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678450, - "trait_key": "age", - "trait_value": 19 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "b984486a-81ea-4ff9-8d4e-865b1e69fdc4", - "identifier": "2b051612-8a49-4e04-9500-5daedb8fec88", - "created_date": "2021-12-15T14:40:00.881523", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2b051612-8a49-4e04-9500-5daedb8fec88", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 99 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103805 - }, - "response": { - "traits": [ - { - "id": 26678451, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678452, - "trait_key": "age", - "trait_value": 99 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "6f498939-34ef-4857-a575-e1411aeee122", - "identifier": "d73a7a70-a8b4-4f98-978a-ebd08cbf2542", - "created_date": "2021-12-15T14:40:00.881529", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d73a7a70-a8b4-4f98-978a-ebd08cbf2542", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 58 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103806 - }, - "response": { - "traits": [ - { - "id": 26678453, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678454, - "trait_key": "age", - "trait_value": 58 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "e83f2397-43de-4b2f-ba5b-6ead257b4d52", - "identifier": "d9b9b9e5-36aa-406e-bda6-71cb99be60f5", - "created_date": "2021-12-15T14:40:00.881535", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d9b9b9e5-36aa-406e-bda6-71cb99be60f5", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "trait_key": "age", - "trait_value": 28 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103808 - }, - "response": { - "traits": [ - { - "id": 26678455, - "trait_key": "favourite_colour", - "trait_value": "orange" - }, - { - "id": 26678456, - "trait_key": "age", - "trait_value": 28 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "1ab52980-b736-4207-bd0b-d068c6e78e83", - "identifier": "560cdbac-dfd9-4536-b65b-6654d575058a", - "created_date": "2021-12-15T14:40:00.881541", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_560cdbac-dfd9-4536-b65b-6654d575058a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 85 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103811 - }, - "response": { - "traits": [ - { - "id": 26678457, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678458, - "trait_key": "age", - "trait_value": 85 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "65a9c511-177d-4d20-9dfb-6771efeb71f9", - "identifier": "be3348ec-6fd9-4b6d-a86a-fd69600855b2", - "created_date": "2021-12-15T14:40:00.881546", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_be3348ec-6fd9-4b6d-a86a-fd69600855b2", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 9 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103812 - }, - "response": { - "traits": [ - { - "id": 26678459, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678460, - "trait_key": "age", - "trait_value": 9 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "45dbc669-d3ba-45cc-b31e-67a4db3a9ea7", - "identifier": "0cfd0d72-4de4-4ed7-9cfb-d80dc3dacead", - "created_date": "2021-12-15T14:40:00.881552", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_0cfd0d72-4de4-4ed7-9cfb-d80dc3dacead", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 47 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103813 - }, - "response": { - "traits": [ - { - "id": 26678461, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678462, - "trait_key": "age", - "trait_value": 47 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "baz", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "79a61937-84b0-400a-b4c3-d5e4a0c61e85", - "identifier": "93f06180-cee7-428e-8385-1206895e4313", - "created_date": "2021-12-15T14:40:00.881557", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_93f06180-cee7-428e-8385-1206895e4313", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 42 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103814 - }, - "response": { - "traits": [ - { - "id": 26678463, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678464, - "trait_key": "age", - "trait_value": 42 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "18e33321-bb8b-4ed0-ab00-e01a19f64071", - "identifier": "18edb157-34cc-4896-aa35-76a7ee68fe68", - "created_date": "2021-12-15T14:40:00.881563", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_18edb157-34cc-4896-aa35-76a7ee68fe68", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 46 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103815 - }, - "response": { - "traits": [ - { - "id": 26678465, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678466, - "trait_key": "age", - "trait_value": 46 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "35596db0-cad3-4b34-8171-cb09b7576305", - "identifier": "e7656d90-7da5-4ce1-b647-36cd977d58fa", - "created_date": "2021-12-15T14:40:00.881568", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_e7656d90-7da5-4ce1-b647-36cd977d58fa", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 34 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103817 - }, - "response": { - "traits": [ - { - "id": 26678467, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678468, - "trait_key": "age", - "trait_value": 34 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "71c30607-114b-47cf-b956-33b2d190cbe2", - "identifier": "d5a54a43-625b-4878-b3fa-120a2bfdd86e", - "created_date": "2021-12-15T14:40:00.881574", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d5a54a43-625b-4878-b3fa-120a2bfdd86e", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 56 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103818 - }, - "response": { - "traits": [ - { - "id": 26678469, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678470, - "trait_key": "age", - "trait_value": 56 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "1746ccce-f02f-410f-83ad-03856ceeeceb", - "identifier": "23edd289-5188-4af0-b0bf-64c42f73f2f4", - "created_date": "2021-12-15T14:40:00.881579", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_23edd289-5188-4af0-b0bf-64c42f73f2f4", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "trait_key": "age", - "trait_value": 77 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103819 - }, - "response": { - "traits": [ - { - "id": 26678471, - "trait_key": "favourite_colour", - "trait_value": "yellow" - }, - { - "id": 26678472, - "trait_key": "age", - "trait_value": 77 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "1a441f46-8d4b-4a81-9b42-ba5b392f20c9", - "identifier": "41f0b1f5-93a1-43c0-afb7-bce9dc20aac0", - "created_date": "2021-12-15T14:40:00.881585", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_41f0b1f5-93a1-43c0-afb7-bce9dc20aac0", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 48 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103820 - }, - "response": { - "traits": [ - { - "id": 26678473, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678474, - "trait_key": "age", - "trait_value": 48 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "8357857d-6166-4f7c-ac9c-6af97f703c3e", - "identifier": "d3f16e64-9cf8-477c-a09b-7b60723c1694", - "created_date": "2021-12-15T14:40:00.881591", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_d3f16e64-9cf8-477c-a09b-7b60723c1694", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "trait_key": "age", - "trait_value": 62 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103821 - }, - "response": { - "traits": [ - { - "id": 26678475, - "trait_key": "favourite_colour", - "trait_value": "green" - }, - { - "id": 26678476, - "trait_key": "age", - "trait_value": 62 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "d4ae7c03-814f-41f2-a6de-5a28ce044770", - "identifier": "957d39a5-6e97-4026-9d94-be68aa97bf1b", - "created_date": "2021-12-15T14:40:00.881596", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_957d39a5-6e97-4026-9d94-be68aa97bf1b", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 30 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103822 - }, - "response": { - "traits": [ - { - "id": 26678477, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678478, - "trait_key": "age", - "trait_value": 30 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "7e6dabdf-9e65-4949-8dd4-21fe0c297855", - "identifier": "53273d70-2f37-4c43-8979-e0426f7ac375", - "created_date": "2021-12-15T14:40:00.881602", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_53273d70-2f37-4c43-8979-e0426f7ac375", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 89 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103823 - }, - "response": { - "traits": [ - { - "id": 26678479, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678480, - "trait_key": "age", - "trait_value": 89 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "a050d1a1-d53a-49ad-b5a9-91ac82bb66c7", - "identifier": "4ab15967-c00b-4a6b-8da6-0a9ef67683fd", - "created_date": "2021-12-15T14:40:00.881607", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_4ab15967-c00b-4a6b-8da6-0a9ef67683fd", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "trait_key": "age", - "trait_value": 92 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103824 - }, - "response": { - "traits": [ - { - "id": 26678481, - "trait_key": "favourite_colour", - "trait_value": "blue" - }, - { - "id": 26678482, - "trait_key": "age", - "trait_value": 92 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - }, - { - "identity": { - "identity_uuid": "c6518ef6-1b38-4d01-a058-e98f701f6253", - "identifier": "2448af3b-bf5c-493b-9bce-13be5d6e697a", - "created_date": "2021-12-15T14:40:00.881614", - "composite_key": "n9fbf9h3v4fFgH3U3ngWhb_2448af3b-bf5c-493b-9bce-13be5d6e697a", - "identity_features": [], - "identity_traits": [ - { - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "trait_key": "age", - "trait_value": 43 - } - ], - "environment_api_key": "n9fbf9h3v4fFgH3U3ngWhb", - "django_id": 32103825 - }, - "response": { - "traits": [ - { - "id": 26678483, - "trait_key": "favourite_colour", - "trait_value": "red" - }, - { - "id": 26678484, - "trait_key": "age", - "trait_value": 43 - } - ], - "flags": [ - { - "id": 78978, - "feature": { - "id": 15058, - "name": "string_feature", - "created_date": "2021-11-29T17:15:51.694223Z", - "description": null, - "initial_value": "foo", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": "foo", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78980, - "feature": { - "id": 15059, - "name": "integer_feature", - "created_date": "2021-11-29T17:16:11.288134Z", - "description": null, - "initial_value": "1234", - "default_enabled": true, - "type": "STANDARD" - }, - "feature_state_value": 1234, - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78982, - "feature": { - "id": 15060, - "name": "basic_flag", - "created_date": "2021-11-29T17:16:25.449058Z", - "description": null, - "initial_value": null, - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": null, - "enabled": false, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78984, - "feature": { - "id": 15061, - "name": "float_feature", - "created_date": "2021-11-29T17:16:43.961385Z", - "description": null, - "initial_value": "12.34", - "default_enabled": false, - "type": "STANDARD" - }, - "feature_state_value": "12.34", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - }, - { - "id": 78986, - "feature": { - "id": 15062, - "name": "mv_feature", - "created_date": "2021-11-29T17:17:23.645334Z", - "description": null, - "initial_value": "foo", - "default_enabled": false, - "type": "MULTIVARIATE" - }, - "feature_state_value": "bar", - "enabled": true, - "environment": 12561, - "identity": null, - "feature_segment": null - } - ] - } - } - ] -} \ No newline at end of file diff --git a/tests/engine/engine-tests/engine-test-data/readme.md b/tests/engine/engine-tests/engine-test-data/readme.md deleted file mode 100644 index 64002cd..0000000 --- a/tests/engine/engine-tests/engine-test-data/readme.md +++ /dev/null @@ -1,30 +0,0 @@ -# Engine Test Data - -This repository contains a single directory containing json files that can be used to test that any Flagsmith engine -written in a given language is correct. - -Each JSON file should consist of a single object in the following format. - -```json -{ - "environment": {...}, // the environment document as found in DynamoDB - "identities_and_responses": [ - { - "identity": {...}, // the identity as found in DynamoDB, - "response": {...}, // the response that was obtained from the current API - } - ] -} -``` - -To use this data, you will need to write a test case in the repository which contains the engine code and include -this repository as a submodule to get access to the json files. - -To add the git submodule: - -```bash -git submodule add git@github.com:Flagsmith/engine-test-data.git tests/engine_tests/engine-test-data -``` - -An example of how to use the test data can be found in the flagsmith-flag-engine repository -[here](https://github.com/Flagsmith/flagsmith-engine/blob/main/tests/engine_tests/test_engine.py). From e121229a6812ec057ed6e86f3bc8fc1991d15f9a Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 10:25:05 +0200 Subject: [PATCH 40/56] chore: fix tests running for submodule with test data --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3761f20..1af095d 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "license": "MIT", "scripts": { "lint": "prettier --write .", - "test": "jest --coverage --coverageReporters='text'", + "get_test_data": "git submodule add git@github.com:Flagsmith/engine-test-data.git tests/engine/engine-tests/engine-test-data/", + "test": "npm run get_test_data; jest --coverage --coverageReporters='text'", "test:watch": "jest --coverage --watch --coverageReporters='text'", "test:debug": "node --inspect-brk node_modules/.bin/jest --coverage --watch --coverageReporters='text'", "build": "tsc", @@ -67,4 +68,4 @@ "ts-jest": "^27.1.3", "typescript": "^4.6.2" } -} +} \ No newline at end of file From 7d92229392790115b5b71965ca07a4367220c004 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 10:33:59 +0200 Subject: [PATCH 41/56] chore: wip on submodule --- .gitmodules | 3 --- tests/engine/engine-tests/engine-test-data | 1 - 2 files changed, 4 deletions(-) delete mode 160000 tests/engine/engine-tests/engine-test-data diff --git a/.gitmodules b/.gitmodules index 426ec2c..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "tests/engine/engine-tests/engine-test-data"] - path = tests/engine/engine-tests/engine-test-data - url = git@github.com:Flagsmith/engine-test-data.git diff --git a/tests/engine/engine-tests/engine-test-data b/tests/engine/engine-tests/engine-test-data deleted file mode 160000 index d4c595f..0000000 --- a/tests/engine/engine-tests/engine-test-data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d4c595f86d75ef9340e678a5e447d8d68f9a7aaa From 32e0bb99f6371f37793177ddb347034da3f086eb Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 10:40:18 +0200 Subject: [PATCH 42/56] chore: clear old submodule --- .gitmodules | 3 +++ tests/engine/engine-tests/engine-test-data | 1 + 2 files changed, 4 insertions(+) create mode 160000 tests/engine/engine-tests/engine-test-data diff --git a/.gitmodules b/.gitmodules index e69de29..426ec2c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/engine/engine-tests/engine-test-data"] + path = tests/engine/engine-tests/engine-test-data + url = git@github.com:Flagsmith/engine-test-data.git diff --git a/tests/engine/engine-tests/engine-test-data b/tests/engine/engine-tests/engine-test-data new file mode 160000 index 0000000..d4c595f --- /dev/null +++ b/tests/engine/engine-tests/engine-test-data @@ -0,0 +1 @@ +Subproject commit d4c595f86d75ef9340e678a5e447d8d68f9a7aaa From 7bbeea53d755be19dfd6445faaa07ca4040dde05 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 10:50:46 +0200 Subject: [PATCH 43/56] fix: get test data after clone --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1af095d..0f1f242 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,8 @@ "license": "MIT", "scripts": { "lint": "prettier --write .", - "get_test_data": "git submodule add git@github.com:Flagsmith/engine-test-data.git tests/engine/engine-tests/engine-test-data/", "test": "npm run get_test_data; jest --coverage --coverageReporters='text'", + "get_test_data": "git submodule update --init", "test:watch": "jest --coverage --watch --coverageReporters='text'", "test:debug": "node --inspect-brk node_modules/.bin/jest --coverage --watch --coverageReporters='text'", "build": "tsc", From e2c3c27cd43120347b1ff5c317d89a9656f7c055 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 10:56:27 +0200 Subject: [PATCH 44/56] fix: checkout submodules on the action stage --- .github/workflows/pull_request.yaml | 66 ++++++++++++++++------------- package.json | 3 +- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index ef1766f..3e30edc 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -1,33 +1,41 @@ name: Unit/Integration Tests on: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - push: - branches: - - main + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review + push: + branches: + - main jobs: - build-and-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: '15.x' - - name: cache node modules - uses: actions/cache@v1 - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: | - npm-${{ hashFiles('package-lock.json') }} - npm- - - run: npm i -g npm@7.0.2 - - run: npm install - - run: npm test - env: - CI: true + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Checkout submodules # checkout rest + shell: bash + run: | + # If your submodules are configured to use SSH instead of HTTPS please uncomment the following line + git config --global url."https://github.com/".insteadOf "git@github.com:" + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + - uses: actions/setup-node@v1 + with: + node-version: "15.x" + - name: cache node modules + uses: actions/cache@v1 + with: + path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS + key: npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + npm-${{ hashFiles('package-lock.json') }} + npm- + - run: npm i -g npm@7.0.2 + - run: npm install + - run: npm test + env: + CI: true diff --git a/package.json b/package.json index 0f1f242..3598e74 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,7 @@ "license": "MIT", "scripts": { "lint": "prettier --write .", - "test": "npm run get_test_data; jest --coverage --coverageReporters='text'", - "get_test_data": "git submodule update --init", + "test": "jest --coverage --coverageReporters='text'", "test:watch": "jest --coverage --watch --coverageReporters='text'", "test:debug": "node --inspect-brk node_modules/.bin/jest --coverage --watch --coverageReporters='text'", "build": "tsc", From 92fc1feb3afc442b8ef434559155193975cc7713 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 19 May 2022 13:13:32 +0200 Subject: [PATCH 45/56] chore: additional tests --- tests/sdk/analytics.test.ts | 11 +++++++++++ tests/sdk/flagsmith.test.ts | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/tests/sdk/analytics.test.ts b/tests/sdk/analytics.test.ts index 7bd106f..d0505d1 100644 --- a/tests/sdk/analytics.test.ts +++ b/tests/sdk/analytics.test.ts @@ -36,6 +36,17 @@ test('test_analytics_processor_flush_post_request_data_match_ananlytics_data', a }); }); +jest.useFakeTimers() +test('test_analytics_processor_flush_post_request_data_match_ananlytics_data_test', async () => { + const aP = analyticsProcessor(); + aP.trackFeature(1); + setTimeout(() => { + aP.trackFeature(2); + expect(fetch).toHaveBeenCalledTimes(1); + }, 15000); + jest.runOnlyPendingTimers(); +}); + test('test_analytics_processor_flush_early_exit_if_analytics_data_is_empty', async () => { const aP = analyticsProcessor(); await aP.flush(); diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 1f3bb0d..825590c 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -23,6 +23,16 @@ test('test_flagsmith_starts_polling_manager_on_init_if_enabled', () => { expect(EnvironmentDataPollingManager).toBeCalled(); }); +test('test_flagsmith_local_evaluation_key_required', () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + new Flagsmith({ + environmentKey: 'bad.key', + enableLocalEvaluation: true + }); + expect(EnvironmentDataPollingManager).toBeCalled(); +}); + test('test_update_environment_sets_environment', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); From 8db2de4bb8b7737b3cc8a949a5423f817bc16e2c Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Fri, 20 May 2022 12:43:24 +0200 Subject: [PATCH 46/56] feat: add caching & tests --- sdk/index.ts | 67 ++++++++-- sdk/types.ts | 8 ++ tests/sdk/flagsmith-cache.test.ts | 122 ++++++++++++++++++ tests/sdk/flagsmith.test.ts | 197 +++++++++++++++++++++++++++++- tests/sdk/polling.test.ts | 25 ++++ tests/sdk/utils.ts | 23 +++- 6 files changed, 426 insertions(+), 16 deletions(-) create mode 100644 sdk/types.ts create mode 100644 tests/sdk/flagsmith-cache.test.ts diff --git a/sdk/index.ts b/sdk/index.ts index 7c527eb..3229e78 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -12,6 +12,7 @@ import { EnvironmentDataPollingManager } from './polling_manager'; import { generateIdentitiesData, retryFetch } from './utils'; import { SegmentModel } from '../flagsmith-engine/segments/models'; import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators'; +import { FlagsmithCache } from './types'; const DEFAULT_API_URL = 'https://api.flagsmith.com/api/v1/'; @@ -26,6 +27,8 @@ export class Flagsmith { enableAnalytics: boolean = false; defaultFlagHandler?: (featureName: string) => DefaultFlag; + cache?: FlagsmithCache; + environmentFlagsUrl: string; identitiesUrl: string; environmentUrl: string; @@ -73,6 +76,7 @@ export class Flagsmith { retries?: number; enableAnalytics?: boolean; defaultFlagHandler?: (featureName: string) => DefaultFlag; + cache?: FlagsmithCache, }) { this.environmentKey = data.environmentKey; this.apiUrl = data.apiUrl || this.apiUrl; @@ -89,6 +93,19 @@ export class Flagsmith { this.identitiesUrl = `${this.apiUrl}identities/`; this.environmentUrl = `${this.apiUrl}environment-document/`; + if (!!data.cache) { + const missingMethods: string[] = ['has', 'get', 'set'].filter(method => data.cache && !data.cache[method]); + + if (missingMethods.length > 0) { + throw new Error( + `Please implement the following methods in your cache: ${missingMethods.join( + ', ' + )}` + ); + } + this.cache = data.cache; + } + if (this.enableLocalEvaluation) { if (!this.environmentKey.startsWith('ser.')) { console.error( @@ -105,10 +122,10 @@ export class Flagsmith { this.analyticsProcessor = data.enableAnalytics ? new AnalyticsProcessor({ - environmentKey: this.environmentKey, - baseApiUrl: this.apiUrl, - timeout: this.requestTimeoutSeconds - }) + environmentKey: this.environmentKey, + baseApiUrl: this.apiUrl, + timeout: this.requestTimeoutSeconds + }) : undefined; } /** @@ -117,8 +134,12 @@ export class Flagsmith { * @returns Flags object holding all the flags for the current environment. */ async getEnvironmentFlags(): Promise { + const cachedItem = !!this.cache && await this.cache.get(`flags`); + if (!!cachedItem) { + return cachedItem; + } if (this.environment) { - return new Promise(resolve => resolve(this.getEnvironmentFlagsFromDocument())); + return this.getEnvironmentFlagsFromDocument(); } return this.getEnvironmentFlagsFromApi(); @@ -134,7 +155,11 @@ export class Flagsmith { Flagsmith, e.g. {"num_orders": 10} * @returns Flags object holding all the flags for the given identity. */ - getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { + async getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise { + const cachedItem = !!this.cache && await this.cache.get(`flags-${identifier}`); + if (!!cachedItem) { + return cachedItem; + } traits = traits || {}; if (this.enableLocalEvaluation) { return new Promise(resolve => @@ -247,15 +272,19 @@ export class Flagsmith { return buildEnvironmentModel(environment_data); } - private getEnvironmentFlagsFromDocument() { - return Flags.fromFeatureStateModels({ + private async getEnvironmentFlagsFromDocument(): Promise { + const flags = Flags.fromFeatureStateModels({ featureStates: getEnvironmentFeatureStates(this.environment), analyticsProcessor: this.analyticsProcessor, defaultFlagHandler: this.defaultFlagHandler }); + if (!!this.cache) { + await this.cache.set('flags', flags); + } + return flags; } - private getIdentityFlagsFromDocument(identifier: string, traits: { [key: string]: any }) { + private async getIdentityFlagsFromDocument(identifier: string, traits: { [key: string]: any }): Promise { const identityModel = this.buildIdentityModel( identifier, Object.keys(traits).map(key => ({ @@ -266,21 +295,31 @@ export class Flagsmith { const featureStates = getIdentityFeatureStates(this.environment, identityModel); - return Flags.fromFeatureStateModels({ + const flags = Flags.fromFeatureStateModels({ featureStates: featureStates, analyticsProcessor: this.analyticsProcessor, defaultFlagHandler: this.defaultFlagHandler }); + + if (!!this.cache) { + await this.cache.set(`flags-${identifier}`, flags); + } + + return flags; } private async getEnvironmentFlagsFromApi() { try { const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET'); - return Flags.fromAPIFlags({ + const flags = Flags.fromAPIFlags({ apiFlags: apiFlags, analyticsProcessor: this.analyticsProcessor, defaultFlagHandler: this.defaultFlagHandler }); + if (!!this.cache) { + await this.cache.set('flags', flags); + } + return flags; } catch (e) { if (this.defaultFlagHandler) { return new Flags({ @@ -297,11 +336,15 @@ export class Flagsmith { try { const data = generateIdentitiesData(identifier, traits); const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data); - return Flags.fromAPIFlags({ + const flags = Flags.fromAPIFlags({ apiFlags: jsonResponse['flags'], analyticsProcessor: this.analyticsProcessor, defaultFlagHandler: this.defaultFlagHandler }); + if (!!this.cache) { + await this.cache.set(`flags-${identifier}`, flags); + } + return flags; } catch (e) { if (this.defaultFlagHandler) { return new Flags({ diff --git a/sdk/types.ts b/sdk/types.ts new file mode 100644 index 0000000..99f27e6 --- /dev/null +++ b/sdk/types.ts @@ -0,0 +1,8 @@ +import { Flags } from "./models"; + +export interface FlagsmithCache { + get(key: string): Promise; + set(key: string, value: Flags): Promise; + has(key: string): Promise; + [key: string]: any; +} diff --git a/tests/sdk/flagsmith-cache.test.ts b/tests/sdk/flagsmith-cache.test.ts new file mode 100644 index 0000000..07510c8 --- /dev/null +++ b/tests/sdk/flagsmith-cache.test.ts @@ -0,0 +1,122 @@ +import fetch, { Headers } from 'node-fetch'; +import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON, TestCache } from './utils'; + +jest.mock('node-fetch'); +jest.mock('../../sdk/polling_manager'); + +const { Response } = jest.requireActual('node-fetch'); + +beforeEach(() => { + // @ts-ignore + jest.clearAllMocks(); +}); + +test('test_wrong_cache_interface_throws_an_error', async () => { + const cache = { + set: () => { }, + get: () => { }, + }; + + expect(() => { const flg = flagsmith({ cache }); }).toThrow(); +}); + +test('test_empty_cache_not_read_but_populated', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const cache = new TestCache(); + const set = jest.spyOn(cache, 'set'); + + const flg = flagsmith({ cache }); + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + + expect(set).toBeCalled(); + expect(await cache.has('flags')).toBe(true); + + expect(fetch).toBeCalledTimes(1); + expect(allFlags[0].enabled).toBe(true); + expect(allFlags[0].value).toBe('some-value'); + expect(allFlags[0].featureName).toBe('some_feature'); +}); + +test('test_api_not_called_when_cache_present', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const cache = new TestCache(); + const set = jest.spyOn(cache, 'set'); + + const flg = flagsmith({ cache }); + await (await flg.getEnvironmentFlags()).allFlags(); + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + + expect(set).toBeCalled(); + expect(await cache.has('flags')).toBe(true); + + expect(fetch).toBeCalledTimes(1); + expect(allFlags[0].enabled).toBe(true); + expect(allFlags[0].value).toBe('some-value'); + expect(allFlags[0].featureName).toBe('some_feature'); +}); + +test('test_api_called_twice_when_no_cache', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const flg = flagsmith(); + await (await flg.getEnvironmentFlags()).allFlags(); + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + + expect(fetch).toBeCalledTimes(2); + expect(allFlags[0].enabled).toBe(true); + expect(allFlags[0].value).toBe('some-value'); + expect(allFlags[0].featureName).toBe('some_feature'); +}); + +test('test_get_environment_flags_uses_local_environment_when_available', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const cache = new TestCache(); + const set = jest.spyOn(cache, 'set'); + + const flg = flagsmith({ cache }); + const model = environmentModel(JSON.parse(environmentJSON())); + flg.environment = model; + + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + + expect(set).toBeCalled(); + expect(fetch).toBeCalledTimes(0); + expect(allFlags[0].enabled).toBe(model.featureStates[0].enabled); + expect(allFlags[0].value).toBe(model.featureStates[0].getValue()); + expect(allFlags[0].featureName).toBe(model.featureStates[0].feature.name); +}); + +test('test_cache_used_for_identity_flags', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + + const cache = new TestCache(); + const set = jest.spyOn(cache, 'set'); + + const identifier = 'identifier'; + const traits = { some_trait: 'some_value' }; + const flg = flagsmith({ cache }); + + (await flg.getIdentityFlags(identifier, traits)).allFlags(); + const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags(); + + expect(set).toBeCalled(); + expect(await cache.has('flags-identifier')).toBe(true); + + expect(fetch).toBeCalledTimes(1); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + +test('test_cache_used_for_all_flags', async () => { }); diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 825590c..5b48686 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -1,8 +1,9 @@ import Flagsmith from '../../sdk'; import { EnvironmentDataPollingManager } from '../../sdk/polling_manager'; -import fetch, { Headers } from 'node-fetch'; +import fetch from 'node-fetch'; import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils'; import { DefaultFlag } from '../../sdk/models'; +import { delay } from '../../sdk/utils'; jest.mock('node-fetch'); jest.mock('../../sdk/polling_manager'); @@ -26,11 +27,12 @@ test('test_flagsmith_starts_polling_manager_on_init_if_enabled', () => { test('test_flagsmith_local_evaluation_key_required', () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + console.error = jest.fn(); new Flagsmith({ environmentKey: 'bad.key', enableLocalEvaluation: true }); - expect(EnvironmentDataPollingManager).toBeCalled(); + expect(console.error).toBeCalled(); }); test('test_update_environment_sets_environment', async () => { @@ -65,6 +67,19 @@ test('test_get_identity_segments', async () => { const segments2 = await flg.getIdentitySegments('user', { age: 41 }); expect(segments2.length).toEqual(0); }); + + +test('test_get_identity_segments_empty_without_local_eval', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + const flg = new Flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: false + }); + const segments = await flg.getIdentitySegments('user', { age: 21 }); + expect(segments.length).toBe(0); +}); + test('test_get_environment_flags_calls_api_when_no_local_environment', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); @@ -126,6 +141,107 @@ test('test_default_flag_is_used_when_no_environment_flags_returned', async () => const defaultFlagHandler = (featureName: string) => defaultFlag; + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + customHeaders: { + 'X-Test-Header': '1', + } + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + expect(flag.isDefault).toBe(true); + expect(flag.enabled).toBe(defaultFlag.enabled); + expect(flag.value).toBe(defaultFlag.value); +}); + +test('test_analytics_processor_tracks_flags', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + enableAnalytics: true, + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.enabled).toBe(true); + expect(flag.value).toBe('some-value'); +}); + +test('test_getFeatureValue', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + enableAnalytics: true, + }); + + const flags = await flg.getEnvironmentFlags(); + const featureValue = flags.getFeatureValue('some_feature'); + + expect(featureValue).toBe('some-value'); +}); + +test('test_isFeatureEnabled', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + enableAnalytics: true, + }); + + const flags = await flg.getEnvironmentFlags(); + const featureValue = flags.isFeatureEnabled('some_feature'); + + expect(featureValue).toBe(true); +}); + +test('test_fetch_recovers_after_single_API_error', async () => { + fetch + // @ts-ignore + .mockRejectedValueOnce(new Error('Error during fetching the API response')) + .mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + const flg = new Flagsmith({ + environmentKey: 'key', + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + expect(flag.isDefault).toBe(false); + expect(flag.enabled).toBe(true); + expect(flag.value).toBe('some-value'); +}); + +test('test_default_flag_used_after_multiple_API_errors', async () => { + fetch + // @ts-ignore + .mockRejectedValue(new Error('Error during fetching the API response')); + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + const flg = new Flagsmith({ environmentKey: 'key', defaultFlagHandler: defaultFlagHandler @@ -138,6 +254,21 @@ test('test_default_flag_is_used_when_no_environment_flags_returned', async () => expect(flag.value).toBe(defaultFlag.value); }); +test('test_throws_when_no_default_flag_handler_after_multiple_API_errors', async () => { + fetch + // @ts-ignore + .mockRejectedValue(new Error('Error during fetching the API response')); + + const flg = new Flagsmith({ + environmentKey: 'key', + }); + + await expect(async () => { + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + }).rejects.toThrow('Error during fetching the API response'); +}); + test('test_non_200_response_raises_flagsmith_api_error', async () => { const errorResponse403 = new Response('403 Forbidden', { status: 403 @@ -171,6 +302,51 @@ test('test_default_flag_is_not_used_when_environment_flags_returned', async () = expect(flag.value).not.toBe(defaultFlag.value); expect(flag.value).toBe('some-value'); }); + +test('test_default_flag_is_used_when_bad_api_response_happens', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('bad-data'))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(defaultFlag.value); +}); + +test('test_local_evaluation', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + defaultFlagHandler: defaultFlagHandler + }); + + await delay(200); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.value).not.toBe(defaultFlag.value); + expect(flag.value).toBe('some-value'); +}); + test('test_default_flag_is_not_used_when_identity_flags_returned', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); @@ -211,3 +387,20 @@ test('test_default_flag_is_used_when_no_identity_flags_returned', async () => { expect(flag.value).toBe(defaultFlag.value); expect(flag.enabled).toBe(defaultFlag.enabled); }); + +test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_default_flag_handler', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); + + + const flg = new Flagsmith({ + environmentKey: 'key', + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(undefined); + expect(flag.enabled).toBe(false); +}); diff --git a/tests/sdk/polling.test.ts b/tests/sdk/polling.test.ts index d0f7a3a..e93b363 100644 --- a/tests/sdk/polling.test.ts +++ b/tests/sdk/polling.test.ts @@ -9,6 +9,16 @@ beforeEach(() => { Flagsmith.mockClear(); }); +test('test_polling_manager_correctly_stops_if_never_started', async () => { + const flagsmith = new Flagsmith({ + environmentKey: 'key' + }); + + const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); + pollingManager.stop(); + expect(flagsmith.updateEnvironment).not.toHaveBeenCalled(); +}); + test('test_polling_manager_calls_update_environment_on_start', async () => { const flagsmith = new Flagsmith({ environmentKey: 'key' @@ -21,6 +31,21 @@ test('test_polling_manager_calls_update_environment_on_start', async () => { expect(flagsmith.updateEnvironment).toHaveBeenCalled(); }); +test('test_polling_manager_handles_double_start', async () => { + const flagsmith = new Flagsmith({ + environmentKey: 'key' + }); + + const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1); + pollingManager.start(); + await delay(100); + pollingManager.start(); + await delay(500); + pollingManager.stop(); + expect(flagsmith.updateEnvironment).toHaveBeenCalled(); +}); + + test('test_polling_manager_calls_update_environment_on_each_refresh', async () => { const flagsmith = new Flagsmith({ environmentKey: 'key' diff --git a/tests/sdk/utils.ts b/tests/sdk/utils.ts index 7f2f892..0aa2529 100644 --- a/tests/sdk/utils.ts +++ b/tests/sdk/utils.ts @@ -2,9 +2,27 @@ import { readFileSync } from 'fs'; import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util'; import { AnalyticsProcessor } from '../../sdk/analytics'; import Flagsmith from '../../sdk'; +import { FlagsmithCache } from '../../sdk/types'; +import { Flag, Flags } from '../../sdk/models'; const DATA_DIR = __dirname + '/data/'; +export class TestCache implements FlagsmithCache { + cache: Record = {}; + + async get(name: string): Promise { + return this.cache[name]; + } + + async has(name: string): Promise { + return !!this.cache[name]; + } + + async set(name: string, value: Flags) { + this.cache[name] = value; + } +} + export function analyticsProcessor() { return new AnalyticsProcessor({ environmentKey: 'test-key', @@ -16,9 +34,10 @@ export function apiKey(): string { return 'sometestfakekey'; } -export function flagsmith() { +export function flagsmith(params = {}) { return new Flagsmith({ - environmentKey: apiKey() + environmentKey: apiKey(), + ...params, }); } From d69e2a3e3422dd0af7f38baea82d7f2030707eb9 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Sat, 21 May 2022 12:24:24 +0200 Subject: [PATCH 47/56] feat: add onEnvironmentChange callback --- sdk/index.ts | 31 ++++++++++++++++++++-------- tests/sdk/flagsmith.test.ts | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/sdk/index.ts b/sdk/index.ts index 3229e78..217245f 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -27,7 +27,6 @@ export class Flagsmith { enableAnalytics: boolean = false; defaultFlagHandler?: (featureName: string) => DefaultFlag; - cache?: FlagsmithCache; environmentFlagsUrl: string; identitiesUrl: string; @@ -35,6 +34,9 @@ export class Flagsmith { environmentDataPollingManager?: EnvironmentDataPollingManager; environment!: EnvironmentModel; + + private cache?: FlagsmithCache; + private onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void; private analyticsProcessor?: AnalyticsProcessor; /** * A Flagsmith client. @@ -77,6 +79,7 @@ export class Flagsmith { enableAnalytics?: boolean; defaultFlagHandler?: (featureName: string) => DefaultFlag; cache?: FlagsmithCache, + onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void, }) { this.environmentKey = data.environmentKey; this.apiUrl = data.apiUrl || this.apiUrl; @@ -92,6 +95,7 @@ export class Flagsmith { this.environmentFlagsUrl = `${this.apiUrl}flags/`; this.identitiesUrl = `${this.apiUrl}identities/`; this.environmentUrl = `${this.apiUrl}environment-document/`; + this.onEnvironmentChange = data.onEnvironmentChange; if (!!data.cache) { const missingMethods: string[] = ['has', 'get', 'set'].filter(method => data.cache && !data.cache[method]); @@ -213,14 +217,23 @@ export class Flagsmith { * You only need to call this if you wish to bypass environmentRefreshIntervalSeconds. */ async updateEnvironment() { - const request = this.getEnvironmentFromApi(); - if (!this.environmentPromise) { - this.environmentPromise = request.then(res => { - this.environment = res; - }); - await this.environmentPromise; - } else { - this.environment = await request; + try { + const request = this.getEnvironmentFromApi(); + if (!this.environmentPromise) { + this.environmentPromise = request.then(res => { + this.environment = res; + }); + await this.environmentPromise; + } else { + this.environment = await request; + } + if (this.onEnvironmentChange) { + this.onEnvironmentChange(null, this.environment); + } + } catch (e) { + if (this.onEnvironmentChange) { + this.onEnvironmentChange(e as Error, this.environment); + } } } diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 5b48686..f2da326 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -4,6 +4,7 @@ import fetch from 'node-fetch'; import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils'; import { DefaultFlag } from '../../sdk/models'; import { delay } from '../../sdk/utils'; +import { EnvironmentModel } from '../../flagsmith-engine/environments/models'; jest.mock('node-fetch'); jest.mock('../../sdk/polling_manager'); @@ -404,3 +405,43 @@ test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_de expect(flag.value).toBe(undefined); expect(flag.enabled).toBe(false); }); + +test('test onEnvironmentChange is called when provided', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('environmentJSON()'))); + + const callback = { + callback: (e: Error | null, result: EnvironmentModel) => { } + }; + const callbackSpy = jest.spyOn(callback, 'callback'); + + const flg = new Flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + onEnvironmentChange: callback.callback, + }); + + await delay(200); + + expect(callbackSpy).toBeCalled(); +}); + +test('test onEnvironmentChange is called after error', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('aaa'))); + + const callback = { + callback: (e: Error | null, result: EnvironmentModel) => { } + }; + const callbackSpy = jest.spyOn(callback, 'callback'); + + const flg = new Flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + onEnvironmentChange: callback.callback, + }); + + await delay(200); + + expect(callbackSpy).toBeCalled(); +}); \ No newline at end of file From 255a977f831f0d630891787436432a174e8fafdf Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Sat, 21 May 2022 12:41:29 +0200 Subject: [PATCH 48/56] chore: add test for local environment + identity flags --- tests/sdk/flagsmith.test.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index f2da326..2e69d18 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -120,6 +120,26 @@ test('test_get_identity_flags_calls_api_when_no_local_environment_no_traits', as expect(identityFlags[0].value).toBe('some-value'); expect(identityFlags[0].featureName).toBe('some_feature'); }); + +test('test_get_identity_flags_calls_api_when_local_environment_no_traits', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + const identifier = 'identifier'; + + const flg = flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + + }); + + + const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags(); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + test('test_get_identity_flags_calls_api_when_no_local_environment_with_traits', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); @@ -408,7 +428,7 @@ test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_de test('test onEnvironmentChange is called when provided', async () => { // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response('environmentJSON()'))); + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); const callback = { callback: (e: Error | null, result: EnvironmentModel) => { } From de5a9f1656c29b408a4417e1cc222ceccccc95f6 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Sat, 21 May 2022 12:53:14 +0200 Subject: [PATCH 49/56] chore: fix race condition checking for environment flags --- sdk/index.ts | 7 +++++++ tests/sdk/flagsmith.test.ts | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sdk/index.ts b/sdk/index.ts index 217245f..4eaa8da 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -142,6 +142,13 @@ export class Flagsmith { if (!!cachedItem) { return cachedItem; } + if (this.enableLocalEvaluation) { + return new Promise(resolve => + this.environmentPromise!.then(() => { + resolve(this.getEnvironmentFlagsFromDocument()); + }) + ); + } if (this.environment) { return this.getEnvironmentFlagsFromDocument(); } diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 2e69d18..e7c288b 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -358,8 +358,6 @@ test('test_local_evaluation', async () => { defaultFlagHandler: defaultFlagHandler }); - await delay(200); - const flags = await flg.getEnvironmentFlags(); const flag = flags.getFlag('some_feature'); From 60ffc15c7f68797d8f7be7b478c46e2df9b1617b Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Sat, 21 May 2022 13:32:11 +0200 Subject: [PATCH 50/56] chore: add misc tests --- flagsmith-engine/utils/hashing/index.ts | 2 + sdk/analytics.ts | 2 - sdk/index.ts | 6 --- tests/engine/unit/utils.ts | 2 +- tests/sdk/flagsmith-cache.test.ts | 28 +++++++++++++ tests/sdk/flagsmith.test.ts | 53 +++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 9 deletions(-) diff --git a/flagsmith-engine/utils/hashing/index.ts b/flagsmith-engine/utils/hashing/index.ts index 71e3220..c7422f0 100644 --- a/flagsmith-engine/utils/hashing/index.ts +++ b/flagsmith-engine/utils/hashing/index.ts @@ -45,6 +45,8 @@ export function getHashedPercentateForObjIds(objectIds: Array, iterations = const value = (hashedInt.mod(9999).toJSNumber() / 9998) * 100; if (value === 100) { + // we ignore this for it's nearly impossible use case to catch + /* istanbul ignore next */ return getHashedPercentateForObjIds(objectIds, iterations + 1); } diff --git a/sdk/analytics.ts b/sdk/analytics.ts index 7fb2a04..b4181ce 100644 --- a/sdk/analytics.ts +++ b/sdk/analytics.ts @@ -5,8 +5,6 @@ const ANALYTICS_ENDPOINT = 'analytics/flags/'; // Used to control how often we send data(in seconds) const ANALYTICS_TIMER = 10; -const delay = (ms: number) => new Promise(resolve => setTimeout(() => resolve(undefined), ms)); - export class AnalyticsProcessor { private analyticsEndpoint: string; private environmentKey: string; diff --git a/sdk/index.ts b/sdk/index.ts index 4eaa8da..5bea1e6 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -378,12 +378,6 @@ export class Flagsmith { } private buildIdentityModel(identifier: string, traits: { key: string; value: any }[]) { - if (!this.environment) { - throw new FlagsmithClientError( - 'Unable to build identity model when no local environment present.' - ); - } - const traitModels = traits.map(trait => new TraitModel(trait.key, trait.value)); return new IdentityModel('0', traitModels, [], this.environment.apiKey, identifier); } diff --git a/tests/engine/unit/utils.ts b/tests/engine/unit/utils.ts index 8a6af38..cdb73b2 100644 --- a/tests/engine/unit/utils.ts +++ b/tests/engine/unit/utils.ts @@ -87,7 +87,7 @@ export function getEnvironmentFeatureStateForFeatureByName( feature_name: string ): FeatureStateModel | undefined { const features = environment.featureStates.filter(fs => fs.feature.name === feature_name); - return features.length > 0 ? features[0] : undefined; + return features[0]; } export function getEnvironmentFeatureStateForFeature( diff --git a/tests/sdk/flagsmith-cache.test.ts b/tests/sdk/flagsmith-cache.test.ts index 07510c8..1cea4e9 100644 --- a/tests/sdk/flagsmith-cache.test.ts +++ b/tests/sdk/flagsmith-cache.test.ts @@ -119,4 +119,32 @@ test('test_cache_used_for_identity_flags', async () => { expect(identityFlags[0].featureName).toBe('some_feature'); }); +test('test_cache_used_for_identity_flags_local_evaluation', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + + const cache = new TestCache(); + const set = jest.spyOn(cache, 'set'); + + const identifier = 'identifier'; + const traits = { some_trait: 'some_value' }; + const flg = flagsmith({ + cache, + environmentKey: 'ser.key', + enableLocalEvaluation: true, + }); + + (await flg.getIdentityFlags(identifier, traits)).allFlags(); + const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags(); + + expect(set).toBeCalled(); + expect(await cache.has('flags-identifier')).toBe(true); + + expect(fetch).toBeCalledTimes(1); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + test('test_cache_used_for_all_flags', async () => { }); diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index e7c288b..58435a9 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -219,6 +219,24 @@ test('test_getFeatureValue', async () => { expect(featureValue).toBe('some-value'); }); +test('test_update_environment_uses_req_when_inited', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + const identifier = 'identifier'; + + const flg = flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + + }); + + delay(400); + + expect(async () => { + await flg.updateEnvironment(); + }).not.toThrow(); +}); + test('test_isFeatureEnabled', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); @@ -407,6 +425,41 @@ test('test_default_flag_is_used_when_no_identity_flags_returned', async () => { expect(flag.enabled).toBe(defaultFlag.enabled); }); +test('test_default_flag_is_used_when_no_identity_flags_returned_due_to_error', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('bad data'))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(defaultFlag.value); + expect(flag.enabled).toBe(defaultFlag.enabled); +}); + +test('test_throws_when_no_identity_flags_returned_due_to_error', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('bad data'))); + + + const flg = new Flagsmith({ + environmentKey: 'key', + }); + + expect(async () => { + await flg.getIdentityFlags('identifier'); + }).rejects.toThrow(); + +}); + test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_default_flag_handler', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); From ba0cdb55018f5ed81ab741ad4d57cb75929e2fa1 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Sat, 21 May 2022 21:08:00 +0200 Subject: [PATCH 51/56] chore: split sdk main test file --- flagsmith-engine/utils/hashing/index.ts | 3 +- .../identities/identities_builders.test.ts | 13 + tests/sdk/flagsmith-environment-flags.test.ts | 197 ++++++++++++ tests/sdk/flagsmith-identity-flags.test.ts | 140 ++++++++ tests/sdk/flagsmith.test.ts | 302 +----------------- 5 files changed, 353 insertions(+), 302 deletions(-) create mode 100644 tests/sdk/flagsmith-environment-flags.test.ts create mode 100644 tests/sdk/flagsmith-identity-flags.test.ts diff --git a/flagsmith-engine/utils/hashing/index.ts b/flagsmith-engine/utils/hashing/index.ts index c7422f0..87d3935 100644 --- a/flagsmith-engine/utils/hashing/index.ts +++ b/flagsmith-engine/utils/hashing/index.ts @@ -44,8 +44,9 @@ export function getHashedPercentateForObjIds(objectIds: Array, iterations = const hashedInt = bigInt(h2d(hashedValue)); const value = (hashedInt.mod(9999).toJSNumber() / 9998) * 100; + // we ignore this for it's nearly impossible use case to catch + /* istanbul ignore next */ if (value === 100) { - // we ignore this for it's nearly impossible use case to catch /* istanbul ignore next */ return getHashedPercentateForObjIds(objectIds, iterations + 1); } diff --git a/tests/engine/unit/identities/identities_builders.test.ts b/tests/engine/unit/identities/identities_builders.test.ts index 663f286..26976e4 100644 --- a/tests/engine/unit/identities/identities_builders.test.ts +++ b/tests/engine/unit/identities/identities_builders.test.ts @@ -42,6 +42,19 @@ test('test_build_identity_model_from_dictionary_uses_identity_feature_list_for_i expect(identityModel.identityFeatures?.length).toBe(1); }); +test('test_build_identity_model_from_dictionary_uses_identity_feature_list_for_identity_features', () => { + const identity_dict = { + id: 1, + identifier: 'test-identity', + environment_api_key: 'api-key', + created_date: '2021-08-22T06:25:23.406995Z', + }; + + const identityModel = buildIdentityModel(identity_dict); + + expect(identityModel.identityFeatures?.length).toBe(0); +}); + test('test_build_build_identity_model_from_dict_creates_identity_uuid', () => { const identity_model = buildIdentityModel({ identifier: 'test_user', diff --git a/tests/sdk/flagsmith-environment-flags.test.ts b/tests/sdk/flagsmith-environment-flags.test.ts new file mode 100644 index 0000000..6262762 --- /dev/null +++ b/tests/sdk/flagsmith-environment-flags.test.ts @@ -0,0 +1,197 @@ +import Flagsmith from '../../sdk'; +import fetch from 'node-fetch'; +import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils'; +import { DefaultFlag } from '../../sdk/models'; + +jest.mock('node-fetch'); +jest.mock('../../sdk/polling_manager'); +const { Response } = jest.requireActual('node-fetch'); + +beforeEach(() => { + // @ts-ignore + jest.clearAllMocks(); +}); + +test('test_get_environment_flags_calls_api_when_no_local_environment', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const flg = flagsmith(); + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + + expect(fetch).toBeCalledTimes(1); + expect(allFlags[0].enabled).toBe(true); + expect(allFlags[0].value).toBe('some-value'); + expect(allFlags[0].featureName).toBe('some_feature'); +}); + +test('test_get_environment_flags_uses_local_environment_when_available', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const flg = flagsmith(); + const model = environmentModel(JSON.parse(environmentJSON())); + flg.environment = model; + + const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); + expect(fetch).toBeCalledTimes(0); + expect(allFlags[0].enabled).toBe(model.featureStates[0].enabled); + expect(allFlags[0].value).toBe(model.featureStates[0].getValue()); + expect(allFlags[0].featureName).toBe(model.featureStates[0].feature.name); +}); + +test('test_default_flag_is_used_when_no_environment_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify([])))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + customHeaders: { + 'X-Test-Header': '1', + } + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + expect(flag.isDefault).toBe(true); + expect(flag.enabled).toBe(defaultFlag.enabled); + expect(flag.value).toBe(defaultFlag.value); +}); + +test('test_analytics_processor_tracks_flags', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + enableAnalytics: true, + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.enabled).toBe(true); + expect(flag.value).toBe('some-value'); +}); + +test('test_getFeatureValue', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler, + enableAnalytics: true, + }); + + const flags = await flg.getEnvironmentFlags(); + const featureValue = flags.getFeatureValue('some_feature'); + + expect(featureValue).toBe('some-value'); +}); + +test('test_throws_when_no_default_flag_handler_after_multiple_API_errors', async () => { + fetch + // @ts-ignore + .mockRejectedValue(new Error('Error during fetching the API response')); + + const flg = new Flagsmith({ + environmentKey: 'key', + }); + + await expect(async () => { + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + }).rejects.toThrow('Error during fetching the API response'); +}); + +test('test_non_200_response_raises_flagsmith_api_error', async () => { + const errorResponse403 = new Response('403 Forbidden', { + status: 403 + }); + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(errorResponse403)); + + const flg = new Flagsmith({ + environmentKey: 'some' + }); + + await expect(flg.getEnvironmentFlags()).rejects.toThrow(); +}); +test('test_default_flag_is_not_used_when_environment_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.value).not.toBe(defaultFlag.value); + expect(flag.value).toBe('some-value'); +}); + +test('test_default_flag_is_used_when_bad_api_response_happens', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('bad-data'))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(defaultFlag.value); +}); + +test('test_local_evaluation', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getEnvironmentFlags(); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.value).not.toBe(defaultFlag.value); + expect(flag.value).toBe('some-value'); +}); diff --git a/tests/sdk/flagsmith-identity-flags.test.ts b/tests/sdk/flagsmith-identity-flags.test.ts new file mode 100644 index 0000000..510e0a4 --- /dev/null +++ b/tests/sdk/flagsmith-identity-flags.test.ts @@ -0,0 +1,140 @@ +import Flagsmith from '../../sdk'; +import fetch from 'node-fetch'; +import { environmentJSON, flagsmith, identitiesJSON } from './utils'; +import { DefaultFlag } from '../../sdk/models'; + +jest.mock('node-fetch'); +jest.mock('../../sdk/polling_manager'); +const { Response } = jest.requireActual('node-fetch'); + +beforeEach(() => { + // @ts-ignore + jest.clearAllMocks(); +}); + + +test('test_get_identity_flags_calls_api_when_no_local_environment_no_traits', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + const identifier = 'identifier'; + + const flg = flagsmith(); + + const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags(); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + +test('test_get_identity_flags_calls_api_when_local_environment_no_traits', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); + const identifier = 'identifier'; + + const flg = flagsmith({ + environmentKey: 'ser.key', + enableLocalEvaluation: true, + + }); + + + const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags(); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + +test('test_get_identity_flags_calls_api_when_no_local_environment_with_traits', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + const identifier = 'identifier'; + const traits = { some_trait: 'some_value' }; + const flg = flagsmith(); + + const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags(); + + expect(identityFlags[0].enabled).toBe(true); + expect(identityFlags[0].value).toBe('some-value'); + expect(identityFlags[0].featureName).toBe('some_feature'); +}); + +test('test_default_flag_is_not_used_when_identity_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(false); + expect(flag.value).not.toBe(defaultFlag.value); + expect(flag.value).toBe('some-value'); +}); + +test('test_default_flag_is_used_when_no_identity_flags_returned', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(defaultFlag.value); + expect(flag.enabled).toBe(defaultFlag.enabled); +}); + +test('test_default_flag_is_used_when_no_identity_flags_returned_due_to_error', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response('bad data'))); + + const defaultFlag = new DefaultFlag('some-default-value', true); + const defaultFlagHandler = (featureName: string) => defaultFlag; + + const flg = new Flagsmith({ + environmentKey: 'key', + defaultFlagHandler: defaultFlagHandler + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(defaultFlag.value); + expect(flag.enabled).toBe(defaultFlag.enabled); +}); + +test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_default_flag_handler', async () => { + // @ts-ignore + fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); + + + const flg = new Flagsmith({ + environmentKey: 'key', + }); + + const flags = await flg.getIdentityFlags('identifier'); + const flag = flags.getFlag('some_feature'); + + expect(flag.isDefault).toBe(true); + expect(flag.value).toBe(undefined); + expect(flag.enabled).toBe(false); +}); + diff --git a/tests/sdk/flagsmith.test.ts b/tests/sdk/flagsmith.test.ts index 58435a9..aaf0265 100644 --- a/tests/sdk/flagsmith.test.ts +++ b/tests/sdk/flagsmith.test.ts @@ -81,143 +81,10 @@ test('test_get_identity_segments_empty_without_local_eval', async () => { expect(segments.length).toBe(0); }); -test('test_get_environment_flags_calls_api_when_no_local_environment', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); - - const flg = flagsmith(); - const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); - - expect(fetch).toBeCalledTimes(1); - expect(allFlags[0].enabled).toBe(true); - expect(allFlags[0].value).toBe('some-value'); - expect(allFlags[0].featureName).toBe('some_feature'); -}); -test('test_get_environment_flags_uses_local_environment_when_available', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); - - const flg = flagsmith(); - const model = environmentModel(JSON.parse(environmentJSON())); - flg.environment = model; - - const allFlags = await (await flg.getEnvironmentFlags()).allFlags(); - expect(fetch).toBeCalledTimes(0); - expect(allFlags[0].enabled).toBe(model.featureStates[0].enabled); - expect(allFlags[0].value).toBe(model.featureStates[0].getValue()); - expect(allFlags[0].featureName).toBe(model.featureStates[0].feature.name); -}); -test('test_get_identity_flags_calls_api_when_no_local_environment_no_traits', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); - const identifier = 'identifier'; - - const flg = flagsmith(); - - const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags(); - - expect(identityFlags[0].enabled).toBe(true); - expect(identityFlags[0].value).toBe('some-value'); - expect(identityFlags[0].featureName).toBe('some_feature'); -}); - -test('test_get_identity_flags_calls_api_when_local_environment_no_traits', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); - const identifier = 'identifier'; - - const flg = flagsmith({ - environmentKey: 'ser.key', - enableLocalEvaluation: true, - - }); - - - const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags(); - - expect(identityFlags[0].enabled).toBe(true); - expect(identityFlags[0].value).toBe('some-value'); - expect(identityFlags[0].featureName).toBe('some_feature'); -}); -test('test_get_identity_flags_calls_api_when_no_local_environment_with_traits', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); - const identifier = 'identifier'; - const traits = { some_trait: 'some_value' }; - const flg = flagsmith(); - const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags(); - expect(identityFlags[0].enabled).toBe(true); - expect(identityFlags[0].value).toBe('some-value'); - expect(identityFlags[0].featureName).toBe('some_feature'); -}); - -test('test_default_flag_is_used_when_no_environment_flags_returned', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify([])))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - - const defaultFlagHandler = (featureName: string) => defaultFlag; - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler, - customHeaders: { - 'X-Test-Header': '1', - } - }); - - const flags = await flg.getEnvironmentFlags(); - const flag = flags.getFlag('some_feature'); - expect(flag.isDefault).toBe(true); - expect(flag.enabled).toBe(defaultFlag.enabled); - expect(flag.value).toBe(defaultFlag.value); -}); - -test('test_analytics_processor_tracks_flags', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler, - enableAnalytics: true, - }); - - const flags = await flg.getEnvironmentFlags(); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(false); - expect(flag.enabled).toBe(true); - expect(flag.value).toBe('some-value'); -}); - -test('test_getFeatureValue', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler, - enableAnalytics: true, - }); - - const flags = await flg.getEnvironmentFlags(); - const featureValue = flags.getFeatureValue('some_feature'); - - expect(featureValue).toBe('some-value'); -}); test('test_update_environment_uses_req_when_inited', async () => { // @ts-ignore @@ -237,7 +104,7 @@ test('test_update_environment_uses_req_when_inited', async () => { }).not.toThrow(); }); -test('test_isFeatureEnabled', async () => { +test('test_isFeatureEnabled_environment', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); @@ -293,157 +160,7 @@ test('test_default_flag_used_after_multiple_API_errors', async () => { expect(flag.value).toBe(defaultFlag.value); }); -test('test_throws_when_no_default_flag_handler_after_multiple_API_errors', async () => { - fetch - // @ts-ignore - .mockRejectedValue(new Error('Error during fetching the API response')); - - const flg = new Flagsmith({ - environmentKey: 'key', - }); - - await expect(async () => { - const flags = await flg.getEnvironmentFlags(); - const flag = flags.getFlag('some_feature'); - }).rejects.toThrow('Error during fetching the API response'); -}); - -test('test_non_200_response_raises_flagsmith_api_error', async () => { - const errorResponse403 = new Response('403 Forbidden', { - status: 403 - }); - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(errorResponse403)); - - const flg = new Flagsmith({ - environmentKey: 'some' - }); - - await expect(flg.getEnvironmentFlags()).rejects.toThrow(); -}); -test('test_default_flag_is_not_used_when_environment_flags_returned', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(flagsJSON()))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler - }); - - const flags = await flg.getEnvironmentFlags(); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(false); - expect(flag.value).not.toBe(defaultFlag.value); - expect(flag.value).toBe('some-value'); -}); - -test('test_default_flag_is_used_when_bad_api_response_happens', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response('bad-data'))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler - }); - - const flags = await flg.getEnvironmentFlags(); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(true); - expect(flag.value).toBe(defaultFlag.value); -}); - -test('test_local_evaluation', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'ser.key', - enableLocalEvaluation: true, - defaultFlagHandler: defaultFlagHandler - }); - - const flags = await flg.getEnvironmentFlags(); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(false); - expect(flag.value).not.toBe(defaultFlag.value); - expect(flag.value).toBe('some-value'); -}); - -test('test_default_flag_is_not_used_when_identity_flags_returned', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(identitiesJSON()))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler - }); - - const flags = await flg.getIdentityFlags('identifier'); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(false); - expect(flag.value).not.toBe(defaultFlag.value); - expect(flag.value).toBe('some-value'); -}); - -test('test_default_flag_is_used_when_no_identity_flags_returned', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler - }); - - const flags = await flg.getIdentityFlags('identifier'); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(true); - expect(flag.value).toBe(defaultFlag.value); - expect(flag.enabled).toBe(defaultFlag.enabled); -}); - -test('test_default_flag_is_used_when_no_identity_flags_returned_due_to_error', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response('bad data'))); - - const defaultFlag = new DefaultFlag('some-default-value', true); - const defaultFlagHandler = (featureName: string) => defaultFlag; - - const flg = new Flagsmith({ - environmentKey: 'key', - defaultFlagHandler: defaultFlagHandler - }); - - const flags = await flg.getIdentityFlags('identifier'); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(true); - expect(flag.value).toBe(defaultFlag.value); - expect(flag.enabled).toBe(defaultFlag.enabled); -}); test('test_throws_when_no_identity_flags_returned_due_to_error', async () => { // @ts-ignore @@ -460,23 +177,6 @@ test('test_throws_when_no_identity_flags_returned_due_to_error', async () => { }); -test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_default_flag_handler', async () => { - // @ts-ignore - fetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify({ flags: [], traits: [] })))); - - - const flg = new Flagsmith({ - environmentKey: 'key', - }); - - const flags = await flg.getIdentityFlags('identifier'); - const flag = flags.getFlag('some_feature'); - - expect(flag.isDefault).toBe(true); - expect(flag.value).toBe(undefined); - expect(flag.enabled).toBe(false); -}); - test('test onEnvironmentChange is called when provided', async () => { // @ts-ignore fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON()))); From fe39a33df01bf2b6e3e828ef25d3e71740a43d2f Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Tue, 24 May 2022 17:55:25 +0100 Subject: [PATCH 52/56] bump 2.0.0-beta.7 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79c7eb9..c7487fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.6", + "version": "2.0.0-beta.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.6", + "version": "2.0.0-beta.7", "license": "MIT", "dependencies": { "big-integer": "^1.6.51", diff --git a/package.json b/package.json index 3598e74..c5d0d02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flagsmith-nodejs", - "version": "2.0.0-beta.6", + "version": "2.0.0-beta.7", "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.", "main": "build/index.js", "repository": { From b63f4618dfa8916ace399659b045997df059f3d0 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 25 May 2022 13:52:26 +0200 Subject: [PATCH 53/56] chore: add test coverage --- flagsmith-engine/features/models.ts | 6 +++--- flagsmith-engine/index.ts | 2 +- sdk/index.ts | 1 - sdk/utils.ts | 9 ++++----- tests/engine/unit/features/models.test.ts | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/flagsmith-engine/features/models.ts b/flagsmith-engine/features/models.ts index 69c000f..a8223fa 100644 --- a/flagsmith-engine/features/models.ts +++ b/flagsmith-engine/features/models.ts @@ -86,9 +86,9 @@ export class FeatureStateModel { ]); let startPercentage = 0; - const sortedF = this.multivariateFeatureStateValues.sort((a, b) => - !!(a.id && b.id) ? a.id - b.id : a.mvFsValueUuid > b.mvFsValueUuid ? -1 : 1 - ); + const sortedF = this.multivariateFeatureStateValues.sort((a, b) =>{ + return a.id - b.id; + }); for (const myValue of sortedF) { const limit = myValue.percentageAllocation + startPercentage; if (startPercentage <= percentageValue && percentageValue < limit) { diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index 44e45e7..0d91d2e 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -33,7 +33,7 @@ function getIdentityFeatureStatesDict( } // Override with any feature states defined directly the identity - for (const fs of identity.identityFeatures || []) { + for (const fs of identity.identityFeatures) { if (featureStates[fs.feature.id]) { featureStates[fs.feature.id] = fs; } diff --git a/sdk/index.ts b/sdk/index.ts index 5bea1e6..388d88d 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -269,7 +269,6 @@ export class Flagsmith { headers: headers }, this.retries, - 1000, (this.requestTimeoutSeconds || 10) * 1000 ); diff --git a/sdk/utils.ts b/sdk/utils.ts index 8fe8670..e004b45 100644 --- a/sdk/utils.ts +++ b/sdk/utils.ts @@ -2,8 +2,8 @@ import fetch, { Response } from 'node-fetch'; // @ts-ignore if (typeof fetch.default !== 'undefined') fetch = fetch.default; -export function generateIdentitiesData(identifier: string, traits?: { [key: string]: any }) { - const traitsGenerated = Object.entries(traits || {}).map(trait => ({ +export function generateIdentitiesData(identifier: string, traits: { [key: string]: any }) { + const traitsGenerated = Object.entries(traits).map(trait => ({ trait_key: trait[0], trait_value: trait[1] })); @@ -18,9 +18,8 @@ export const delay = (ms: number) => export const retryFetch = ( url: string, - fetchOptions = {}, + fetchOptions: any, retries = 3, - retryDelay = 1000, timeout: number ): Promise => { return new Promise((resolve, reject) => { @@ -32,7 +31,7 @@ export const retryFetch = ( .then(res => resolve(res)) .catch(async err => { if (n > 0) { - await delay(retryDelay); + await delay(1000); wrapper(--n); } else { reject(err); diff --git a/tests/engine/unit/features/models.test.ts b/tests/engine/unit/features/models.test.ts index c6d83a8..7cfa2ac 100644 --- a/tests/engine/unit/features/models.test.ts +++ b/tests/engine/unit/features/models.test.ts @@ -66,7 +66,7 @@ test('test_feature_state_get_value_mv_values', () => { const mvFeatureState = new FeatureStateModel(myFeature, true, 1); mvFeatureState.multivariateFeatureStateValues = [ mvFeatureStateValue1, - mvFeatureStateValue2 + mvFeatureStateValue2, ]; mvFeatureState.setValue(mvFeatureControlValue); From 78cb01c001b1b7f5967f22ae5ee213927c512a5d Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Thu, 26 May 2022 12:40:17 +0200 Subject: [PATCH 54/56] feat: feature segments add --- flagsmith-engine/features/models.ts | 32 +++++++++++++++++++++++++++++ flagsmith-engine/features/util.ts | 14 +++++++++++++ flagsmith-engine/index.ts | 6 +++++- flagsmith-engine/utils/index.ts | 6 ++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/flagsmith-engine/features/models.ts b/flagsmith-engine/features/models.ts index a8223fa..ceb157d 100644 --- a/flagsmith-engine/features/models.ts +++ b/flagsmith-engine/features/models.ts @@ -51,6 +51,7 @@ export class FeatureStateModel { enabled: boolean; djangoID: number; featurestateUUID: string = uuidv4(); + featureSegment?: FeatureSegment; private value: any; multivariateFeatureStateValues: MultivariateFeatureStateValueModel[] = []; @@ -79,6 +80,23 @@ export class FeatureStateModel { return this.value; } + /* + Returns `True` if `this` is higher segment priority than `other` + (i.e. has lower value for featureSegment.priority) + NOTE: + A segment will be considered higher priority only if: + 1. `other` does not have a feature segment(i.e: it is an environment feature state or it's a + feature state with feature segment but from an old document that does not have `featureSegment.priority`) + but `this` does. + 2. `other` have a feature segment with high priority + */ + isHigherSegmentPriority(other: FeatureStateModel): boolean { + if (!other.featureSegment || !this.featureSegment) { + return false; + } + return this.featureSegment.priority < other.featureSegment.priority; + } + getMultivariateValue(identityID: number | string) { const percentageValue = getHashedPercentateForObjIds([ this.djangoID || this.featurestateUUID, @@ -99,3 +117,17 @@ export class FeatureStateModel { return this.value; } } + +export class FeatureSegment { + id: number; + priority: number; + environment: string; + featureStates: FeatureStateModel[] = []; + + constructor(id: number, priority: number, environment: string, featureStates: FeatureStateModel[]) { + this.id = id; + this.priority = priority; + this.environment = environment; + this.featureStates = featureStates || []; + } +} \ No newline at end of file diff --git a/flagsmith-engine/features/util.ts b/flagsmith-engine/features/util.ts index fe9cfe9..36d80d7 100644 --- a/flagsmith-engine/features/util.ts +++ b/flagsmith-engine/features/util.ts @@ -1,5 +1,6 @@ import { FeatureModel, + FeatureSegment, FeatureStateModel, MultivariateFeatureOptionModel, MultivariateFeatureStateValueModel @@ -18,6 +19,10 @@ export function buildFeatureStateModel(featuresStateModelJSON: any): FeatureStat featuresStateModelJSON.uuid ); + featureStateModel.featureSegment = featuresStateModelJSON.feature_segment ? + buildFeatureSegment(featuresStateModelJSON.feature_segment) : + undefined; + const multivariateFeatureStateValues = featuresStateModelJSON.multivariate_feature_state_values ? featuresStateModelJSON.multivariate_feature_state_values.map((fsv: any) => { const featureOption = new MultivariateFeatureOptionModel( @@ -36,3 +41,12 @@ export function buildFeatureStateModel(featuresStateModelJSON: any): FeatureStat return featureStateModel; } + +export function buildFeatureSegment(featureSegmentJSON: any): FeatureSegment { + const featureStates = featureSegmentJSON.feature_states ? featureSegmentJSON.feature_states.map(buildFeatureStateModel) : []; + return new FeatureSegment( + featureSegmentJSON.id, + featureSegmentJSON.priority, + featureSegmentJSON.environment, + featureStates); +} diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index 0d91d2e..35bf291 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -25,9 +25,13 @@ function getIdentityFeatureStatesDict( ); for (const matchingSegment of identitySegments) { for (const featureState of matchingSegment.featureStates) { + if (featureStates[featureState.feature.id]) { + if (featureStates[featureState.feature.id].isHigherSegmentPriority(featureState)) { + continue; + } + } // note that feature states are stored on the segment in descending priority // order so we only care that the last one is added - // TODO: can we optimise this? featureStates[featureState.feature.id] = featureState; } } diff --git a/flagsmith-engine/utils/index.ts b/flagsmith-engine/utils/index.ts index 9470ac0..050ea55 100644 --- a/flagsmith-engine/utils/index.ts +++ b/flagsmith-engine/utils/index.ts @@ -1,3 +1,5 @@ +import { FeatureSegment } from "../features/models"; + export function getCastingFunction(input: any): CallableFunction { switch (typeof input) { case 'boolean': @@ -8,3 +10,7 @@ export function getCastingFunction(input: any): CallableFunction { return (x: any) => String(x); } } + +export function filterFeatureSegments(featureSegments: FeatureSegment[], environmentApiKey: string): FeatureSegment[] { + return featureSegments.filter(fs => fs.environment === environmentApiKey); +} \ No newline at end of file From 0a86930f959d90a57250bf6e5b4187ec0cdfa1a4 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 1 Jun 2022 00:32:25 +0200 Subject: [PATCH 55/56] fix: feature state priority calculation --- flagsmith-engine/features/models.ts | 14 ++++---------- flagsmith-engine/features/util.ts | 7 +------ flagsmith-engine/index.ts | 2 -- flagsmith-engine/utils/index.ts | 6 +++--- tests/engine/engine-tests/engine-test-data | 2 +- 5 files changed, 9 insertions(+), 22 deletions(-) diff --git a/flagsmith-engine/features/models.ts b/flagsmith-engine/features/models.ts index ceb157d..8c8b0d8 100644 --- a/flagsmith-engine/features/models.ts +++ b/flagsmith-engine/features/models.ts @@ -92,11 +92,11 @@ export class FeatureStateModel { */ isHigherSegmentPriority(other: FeatureStateModel): boolean { if (!other.featureSegment || !this.featureSegment) { - return false; + return !!this.featureSegment && !other.featureSegment; } return this.featureSegment.priority < other.featureSegment.priority; } - + getMultivariateValue(identityID: number | string) { const percentageValue = getHashedPercentateForObjIds([ this.djangoID || this.featurestateUUID, @@ -119,15 +119,9 @@ export class FeatureStateModel { } export class FeatureSegment { - id: number; priority: number; - environment: string; - featureStates: FeatureStateModel[] = []; - constructor(id: number, priority: number, environment: string, featureStates: FeatureStateModel[]) { - this.id = id; + constructor(priority: number) { this.priority = priority; - this.environment = environment; - this.featureStates = featureStates || []; } -} \ No newline at end of file +} diff --git a/flagsmith-engine/features/util.ts b/flagsmith-engine/features/util.ts index 36d80d7..0c09b62 100644 --- a/flagsmith-engine/features/util.ts +++ b/flagsmith-engine/features/util.ts @@ -43,10 +43,5 @@ export function buildFeatureStateModel(featuresStateModelJSON: any): FeatureStat } export function buildFeatureSegment(featureSegmentJSON: any): FeatureSegment { - const featureStates = featureSegmentJSON.feature_states ? featureSegmentJSON.feature_states.map(buildFeatureStateModel) : []; - return new FeatureSegment( - featureSegmentJSON.id, - featureSegmentJSON.priority, - featureSegmentJSON.environment, - featureStates); + return new FeatureSegment(featureSegmentJSON.priority); } diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index 35bf291..181f67e 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -30,8 +30,6 @@ function getIdentityFeatureStatesDict( continue; } } - // note that feature states are stored on the segment in descending priority - // order so we only care that the last one is added featureStates[featureState.feature.id] = featureState; } } diff --git a/flagsmith-engine/utils/index.ts b/flagsmith-engine/utils/index.ts index 050ea55..e0f6d53 100644 --- a/flagsmith-engine/utils/index.ts +++ b/flagsmith-engine/utils/index.ts @@ -11,6 +11,6 @@ export function getCastingFunction(input: any): CallableFunction { } } -export function filterFeatureSegments(featureSegments: FeatureSegment[], environmentApiKey: string): FeatureSegment[] { - return featureSegments.filter(fs => fs.environment === environmentApiKey); -} \ No newline at end of file +// export function filterFeatureSegments(featureSegments: FeatureSegment[], environmentApiKey: string): FeatureSegment[] { +// return featureSegments.filter(fs => fs.environment === environmentApiKey); +// } \ No newline at end of file diff --git a/tests/engine/engine-tests/engine-test-data b/tests/engine/engine-tests/engine-test-data index d4c595f..933f2ba 160000 --- a/tests/engine/engine-tests/engine-test-data +++ b/tests/engine/engine-tests/engine-test-data @@ -1 +1 @@ -Subproject commit d4c595f86d75ef9340e678a5e447d8d68f9a7aaa +Subproject commit 933f2ba7aa6430797afc2d053530cfd005b461f6 From d944be55745a77623f3cc2190b3e248c3622b729 Mon Sep 17 00:00:00 2001 From: yuriihorodnyi21 Date: Wed, 1 Jun 2022 00:55:31 +0200 Subject: [PATCH 56/56] chore: remove unused code --- flagsmith-engine/utils/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/flagsmith-engine/utils/index.ts b/flagsmith-engine/utils/index.ts index e0f6d53..f4bd133 100644 --- a/flagsmith-engine/utils/index.ts +++ b/flagsmith-engine/utils/index.ts @@ -10,7 +10,3 @@ export function getCastingFunction(input: any): CallableFunction { return (x: any) => String(x); } } - -// export function filterFeatureSegments(featureSegments: FeatureSegment[], environmentApiKey: string): FeatureSegment[] { -// return featureSegments.filter(fs => fs.environment === environmentApiKey); -// } \ No newline at end of file