flagsmith-nodejs 3.3.2 → 4.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +2 -2
- package/.github/workflows/pull_request.yaml +3 -4
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/environments/models.d.ts +3 -3
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/environments/models.js +20 -13
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/environments/util.d.ts +1 -1
- package/build/cjs/flagsmith-engine/environments/util.js +23 -0
- package/build/cjs/flagsmith-engine/features/models.js +118 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/util.d.ts +1 -1
- package/build/cjs/flagsmith-engine/features/util.js +27 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/models.d.ts +2 -2
- package/build/cjs/flagsmith-engine/identities/models.js +48 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/traits/models.js +5 -4
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/util.d.ts +2 -2
- package/build/cjs/flagsmith-engine/identities/util.js +22 -0
- package/build/cjs/flagsmith-engine/index.d.ts +14 -0
- package/build/cjs/flagsmith-engine/index.js +75 -0
- package/build/cjs/flagsmith-engine/organisations/models.js +21 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/organisations/util.d.ts +1 -1
- package/build/cjs/flagsmith-engine/organisations/util.js +8 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/projects/models.d.ts +2 -2
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/projects/models.js +8 -5
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/projects/util.d.ts +1 -1
- package/build/cjs/flagsmith-engine/projects/util.js +15 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/evaluators.d.ts +4 -4
- package/build/cjs/flagsmith-engine/segments/evaluators.js +37 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/models.d.ts +1 -1
- package/build/cjs/flagsmith-engine/segments/models.js +114 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/util.d.ts +1 -1
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/util.js +9 -11
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/collections.d.ts +1 -1
- package/build/cjs/flagsmith-engine/utils/collections.js +6 -0
- package/build/cjs/flagsmith-engine/utils/errors.js +6 -0
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/hashing/index.js +8 -11
- package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/index.js +5 -5
- package/build/{index.d.ts → cjs/index.d.ts} +3 -3
- package/build/{index.js → cjs/index.js} +17 -17
- package/build/cjs/package.json +1 -0
- package/build/{sdk → cjs/sdk}/analytics.d.ts +3 -0
- package/build/cjs/sdk/analytics.js +73 -0
- package/build/cjs/sdk/errors.js +9 -0
- package/build/{sdk → cjs/sdk}/index.d.ts +19 -18
- package/build/cjs/sdk/index.js +400 -0
- package/build/{sdk → cjs/sdk}/models.d.ts +2 -2
- package/build/cjs/sdk/models.js +101 -0
- package/build/{sdk → cjs/sdk}/offline_handlers.d.ts +1 -1
- package/build/cjs/sdk/offline_handlers.js +46 -0
- package/build/{sdk → cjs/sdk}/polling_manager.d.ts +1 -1
- package/build/cjs/sdk/polling_manager.js +29 -0
- package/build/{sdk → cjs/sdk}/types.d.ts +15 -7
- package/build/cjs/sdk/utils.d.ts +36 -0
- package/build/cjs/sdk/utils.js +63 -0
- package/build/esm/flagsmith-engine/environments/models.d.ts +22 -0
- package/build/esm/flagsmith-engine/environments/models.js +32 -0
- package/build/esm/flagsmith-engine/environments/util.d.ts +3 -0
- package/build/esm/flagsmith-engine/environments/util.js +18 -0
- package/build/esm/flagsmith-engine/features/constants.d.ts +4 -0
- package/build/esm/flagsmith-engine/features/constants.js +4 -0
- package/build/esm/flagsmith-engine/features/models.d.ts +37 -0
- package/build/esm/flagsmith-engine/features/models.js +110 -0
- package/build/esm/flagsmith-engine/features/util.d.ts +4 -0
- package/build/esm/flagsmith-engine/features/util.js +21 -0
- package/build/esm/flagsmith-engine/identities/models.d.ts +15 -0
- package/build/esm/flagsmith-engine/identities/models.js +44 -0
- package/build/esm/flagsmith-engine/identities/traits/models.d.ts +5 -0
- package/build/esm/flagsmith-engine/identities/traits/models.js +8 -0
- package/build/esm/flagsmith-engine/identities/util.d.ts +4 -0
- package/build/esm/flagsmith-engine/identities/util.js +17 -0
- package/build/esm/flagsmith-engine/index.d.ts +14 -0
- package/build/esm/flagsmith-engine/index.js +62 -0
- package/build/esm/flagsmith-engine/organisations/models.d.ts +9 -0
- package/build/esm/flagsmith-engine/organisations/models.js +17 -0
- package/build/esm/flagsmith-engine/organisations/util.d.ts +2 -0
- package/build/esm/flagsmith-engine/organisations/util.js +4 -0
- package/build/esm/flagsmith-engine/projects/models.d.ts +10 -0
- package/build/esm/flagsmith-engine/projects/models.js +13 -0
- package/build/esm/flagsmith-engine/projects/util.d.ts +2 -0
- package/build/esm/flagsmith-engine/projects/util.js +11 -0
- package/build/esm/flagsmith-engine/segments/constants.d.ts +34 -0
- package/build/esm/flagsmith-engine/segments/constants.js +36 -0
- package/build/esm/flagsmith-engine/segments/evaluators.d.ts +7 -0
- package/build/esm/flagsmith-engine/segments/evaluators.js +31 -0
- package/build/esm/flagsmith-engine/segments/models.d.ts +37 -0
- package/build/esm/flagsmith-engine/segments/models.js +102 -0
- package/build/esm/flagsmith-engine/segments/util.d.ts +6 -0
- package/build/esm/flagsmith-engine/segments/util.js +23 -0
- package/build/esm/flagsmith-engine/utils/collections.d.ts +3 -0
- package/build/esm/flagsmith-engine/utils/collections.js +2 -0
- package/build/esm/flagsmith-engine/utils/errors.d.ts +2 -0
- package/build/esm/flagsmith-engine/utils/errors.js +2 -0
- package/build/esm/flagsmith-engine/utils/hashing/index.d.ts +9 -0
- package/build/esm/flagsmith-engine/utils/hashing/index.js +50 -0
- package/build/esm/flagsmith-engine/utils/index.d.ts +1 -0
- package/build/esm/flagsmith-engine/utils/index.js +13 -0
- package/build/esm/index.d.ts +3 -0
- package/build/esm/index.js +4 -0
- package/build/esm/sdk/analytics.d.ts +35 -0
- package/build/esm/sdk/analytics.js +69 -0
- package/build/esm/sdk/errors.d.ts +4 -0
- package/build/esm/sdk/errors.js +4 -0
- package/build/esm/sdk/index.d.ts +131 -0
- package/build/esm/sdk/index.js +390 -0
- package/build/esm/sdk/models.d.ts +55 -0
- package/build/esm/sdk/models.js +94 -0
- package/build/esm/sdk/offline_handlers.d.ts +9 -0
- package/build/esm/sdk/offline_handlers.js +18 -0
- package/build/esm/sdk/polling_manager.d.ts +9 -0
- package/build/esm/sdk/polling_manager.js +25 -0
- package/build/esm/sdk/types.d.ts +38 -0
- package/build/esm/sdk/types.js +1 -0
- package/build/esm/sdk/utils.d.ts +36 -0
- package/build/esm/sdk/utils.js +56 -0
- package/flagsmith-engine/environments/models.ts +3 -3
- package/flagsmith-engine/environments/util.ts +4 -4
- package/flagsmith-engine/features/models.ts +1 -1
- package/flagsmith-engine/features/util.ts +1 -1
- package/flagsmith-engine/identities/models.ts +3 -4
- package/flagsmith-engine/identities/traits/models.ts +0 -1
- package/flagsmith-engine/identities/util.ts +4 -4
- package/flagsmith-engine/index.ts +13 -13
- package/flagsmith-engine/organisations/util.ts +1 -1
- package/flagsmith-engine/projects/models.ts +2 -2
- package/flagsmith-engine/projects/util.ts +4 -4
- package/flagsmith-engine/segments/evaluators.ts +6 -6
- package/flagsmith-engine/segments/models.ts +4 -4
- package/flagsmith-engine/segments/util.ts +3 -3
- package/flagsmith-engine/utils/collections.ts +1 -1
- package/flagsmith-engine/utils/index.ts +1 -1
- package/index.ts +4 -4
- package/package.json +21 -9
- package/sdk/analytics.ts +7 -5
- package/sdk/index.ts +55 -46
- package/sdk/models.ts +2 -3
- package/sdk/offline_handlers.ts +2 -2
- package/sdk/polling_manager.ts +2 -3
- package/sdk/types.ts +35 -24
- package/sdk/utils.ts +49 -29
- package/tests/engine/e2e/engine.test.ts +5 -5
- package/tests/engine/unit/engine.test.ts +5 -5
- package/tests/engine/unit/segments/segment_evaluators.test.ts +9 -9
- package/tests/engine/unit/utils/utils.test.ts +1 -1
- package/tests/sdk/analytics.test.ts +8 -13
- package/tests/sdk/data/identity-with-transient-traits.json +41 -0
- package/tests/sdk/data/transient-identity.json +29 -0
- package/tests/sdk/flagsmith-cache.test.ts +16 -32
- package/tests/sdk/flagsmith-environment-flags.test.ts +21 -36
- package/tests/sdk/flagsmith-identity-flags.test.ts +83 -32
- package/tests/sdk/flagsmith.test.ts +67 -99
- package/tests/sdk/offline-handlers.test.ts +4 -5
- package/tests/sdk/polling.test.ts +6 -8
- package/tests/sdk/utils.ts +19 -15
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.esm.json +7 -0
- package/tsconfig.json +7 -3
- package/vitest.config.ts +17 -0
- package/build/flagsmith-engine/environments/util.js +0 -27
- package/build/flagsmith-engine/features/models.js +0 -132
- package/build/flagsmith-engine/features/util.js +0 -27
- package/build/flagsmith-engine/identities/models.js +0 -113
- package/build/flagsmith-engine/identities/util.js +0 -46
- package/build/flagsmith-engine/index.d.ts +0 -14
- package/build/flagsmith-engine/index.js +0 -127
- package/build/flagsmith-engine/organisations/models.js +0 -21
- package/build/flagsmith-engine/organisations/util.js +0 -8
- package/build/flagsmith-engine/projects/util.js +0 -15
- package/build/flagsmith-engine/segments/evaluators.js +0 -45
- package/build/flagsmith-engine/segments/models.js +0 -147
- package/build/flagsmith-engine/utils/collections.js +0 -26
- package/build/flagsmith-engine/utils/errors.js +0 -26
- package/build/sdk/analytics.js +0 -120
- package/build/sdk/errors.js +0 -34
- package/build/sdk/index.js +0 -594
- package/build/sdk/models.js +0 -149
- package/build/sdk/offline_handlers.js +0 -66
- package/build/sdk/polling_manager.js +0 -72
- package/build/sdk/utils.d.ts +0 -12
- package/build/sdk/utils.js +0 -100
- package/jest.config.js +0 -5
- package/tests/index.js +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/constants.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/constants.js +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/models.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/traits/models.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/organisations/models.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/constants.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/constants.js +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/errors.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/hashing/index.d.ts +0 -0
- /package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/index.d.ts +0 -0
- /package/build/{sdk → cjs/sdk}/errors.d.ts +0 -0
- /package/build/{sdk → cjs/sdk}/types.js +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export function isTraitConfig(traitValue) {
|
|
2
|
+
return !!traitValue && typeof traitValue == 'object' && traitValue.value !== undefined;
|
|
3
|
+
}
|
|
4
|
+
export function generateIdentitiesData(identifier, traits, transient) {
|
|
5
|
+
const traitsGenerated = Object.entries(traits).map(([key, value]) => {
|
|
6
|
+
if (isTraitConfig(value)) {
|
|
7
|
+
return {
|
|
8
|
+
trait_key: key,
|
|
9
|
+
trait_value: value?.value,
|
|
10
|
+
transient: value?.transient,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return {
|
|
15
|
+
trait_key: key,
|
|
16
|
+
trait_value: value,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
if (transient) {
|
|
21
|
+
return {
|
|
22
|
+
identifier: identifier,
|
|
23
|
+
traits: traitsGenerated,
|
|
24
|
+
transient: true
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
identifier: identifier,
|
|
29
|
+
traits: traitsGenerated
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export const delay = (ms) => new Promise(resolve => setTimeout(() => resolve(undefined), ms));
|
|
33
|
+
export const retryFetch = (url,
|
|
34
|
+
// built-in RequestInit type doesn't have dispatcher/agent
|
|
35
|
+
fetchOptions, retries = 3, timeoutMs = 10, // set an overall timeout for this function
|
|
36
|
+
customFetch) => {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const retryWrapper = (n) => {
|
|
39
|
+
customFetch(url, {
|
|
40
|
+
...fetchOptions,
|
|
41
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
42
|
+
})
|
|
43
|
+
.then(res => resolve(res))
|
|
44
|
+
.catch(async (err) => {
|
|
45
|
+
if (n > 0) {
|
|
46
|
+
await delay(1000);
|
|
47
|
+
retryWrapper(--n);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
reject(err);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
retryWrapper(retries);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { FeatureStateModel } from '../features/models';
|
|
2
|
-
import { IdentityModel } from '../identities/models';
|
|
3
|
-
import { ProjectModel } from '../projects/models';
|
|
1
|
+
import { FeatureStateModel } from '../features/models.js';
|
|
2
|
+
import { IdentityModel } from '../identities/models.js';
|
|
3
|
+
import { ProjectModel } from '../projects/models.js';
|
|
4
4
|
|
|
5
5
|
export class EnvironmentAPIKeyModel {
|
|
6
6
|
id: number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { buildFeatureStateModel } from '../features/util';
|
|
2
|
-
import { buildIdentityModel } from '../identities/util';
|
|
3
|
-
import { buildProjectModel } from '../projects/util';
|
|
4
|
-
import { EnvironmentAPIKeyModel, EnvironmentModel } from './models';
|
|
1
|
+
import { buildFeatureStateModel } from '../features/util.js';
|
|
2
|
+
import { buildIdentityModel } from '../identities/util.js';
|
|
3
|
+
import { buildProjectModel } from '../projects/util.js';
|
|
4
|
+
import { EnvironmentAPIKeyModel, EnvironmentModel } from './models.js';
|
|
5
5
|
|
|
6
6
|
export function buildEnvironmentModel(environmentJSON: any) {
|
|
7
7
|
const project = buildProjectModel(environmentJSON.project);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
FeatureStateModel,
|
|
5
5
|
MultivariateFeatureOptionModel,
|
|
6
6
|
MultivariateFeatureStateValueModel
|
|
7
|
-
} from './models';
|
|
7
|
+
} from './models.js';
|
|
8
8
|
|
|
9
9
|
export function buildFeatureModel(featuresModelJSON: any): FeatureModel {
|
|
10
10
|
return new FeatureModel(featuresModelJSON.id, featuresModelJSON.name, featuresModelJSON.type);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { TraitModel } from './traits/models';
|
|
1
|
+
import { IdentityFeaturesList } from '../utils/collections.js';
|
|
2
|
+
import { TraitModel } from './traits/models.js';
|
|
4
3
|
|
|
5
4
|
const { v4: uuidv4 } = require('uuid');
|
|
6
5
|
|
|
@@ -20,7 +19,7 @@ export class IdentityModel {
|
|
|
20
19
|
environmentApiKey: string,
|
|
21
20
|
identifier: string,
|
|
22
21
|
identityUuid?: string,
|
|
23
|
-
djangoID?: number
|
|
22
|
+
djangoID?: number,
|
|
24
23
|
) {
|
|
25
24
|
this.identityUuid = identityUuid || uuidv4();
|
|
26
25
|
this.createdDate = Date.parse(created_date) || Date.now();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { buildFeatureStateModel } from '../features/util';
|
|
2
|
-
import { IdentityFeaturesList } from '../utils/collections';
|
|
3
|
-
import { IdentityModel } from './models';
|
|
4
|
-
import { TraitModel } from './traits/models';
|
|
1
|
+
import { buildFeatureStateModel } from '../features/util.js';
|
|
2
|
+
import { IdentityFeaturesList } from '../utils/collections.js';
|
|
3
|
+
import { IdentityModel } from './models.js';
|
|
4
|
+
import { TraitModel } from './traits/models.js';
|
|
5
5
|
|
|
6
6
|
export function buildTraitModel(traitJSON: any): TraitModel {
|
|
7
7
|
return new TraitModel(traitJSON.trait_key, traitJSON.trait_value);
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { EnvironmentModel } from './environments/models';
|
|
2
|
-
import { FeatureStateModel } from './features/models';
|
|
3
|
-
import { IdentityModel } from './identities/models';
|
|
4
|
-
import { TraitModel } from './identities/traits/models';
|
|
5
|
-
import { getIdentitySegments } from './segments/evaluators';
|
|
6
|
-
import { SegmentModel } from './segments/models';
|
|
7
|
-
import { FeatureStateNotFound } from './utils/errors';
|
|
1
|
+
import { EnvironmentModel } from './environments/models.js';
|
|
2
|
+
import { FeatureStateModel } from './features/models.js';
|
|
3
|
+
import { IdentityModel } from './identities/models.js';
|
|
4
|
+
import { TraitModel } from './identities/traits/models.js';
|
|
5
|
+
import { getIdentitySegments } from './segments/evaluators.js';
|
|
6
|
+
import { SegmentModel } from './segments/models.js';
|
|
7
|
+
import { FeatureStateNotFound } from './utils/errors.js';
|
|
8
8
|
|
|
9
|
-
export { EnvironmentModel } from './environments/models';
|
|
10
|
-
export { FeatureStateModel } from './features/models';
|
|
11
|
-
export { IdentityModel } from './identities/models';
|
|
12
|
-
export { TraitModel } from './identities/traits/models';
|
|
13
|
-
export { SegmentModel } from './segments/models';
|
|
14
|
-
export { OrganisationModel } from './organisations/models';
|
|
9
|
+
export { EnvironmentModel } from './environments/models.js';
|
|
10
|
+
export { FeatureStateModel } from './features/models.js';
|
|
11
|
+
export { IdentityModel } from './identities/models.js';
|
|
12
|
+
export { TraitModel } from './identities/traits/models.js';
|
|
13
|
+
export { SegmentModel } from './segments/models.js';
|
|
14
|
+
export { OrganisationModel } from './organisations/models.js';
|
|
15
15
|
|
|
16
16
|
function getIdentityFeatureStatesDict(
|
|
17
17
|
environment: EnvironmentModel,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { OrganisationModel } from '../organisations/models';
|
|
2
|
-
import { SegmentModel } from '../segments/models';
|
|
1
|
+
import { OrganisationModel } from '../organisations/models.js';
|
|
2
|
+
import { SegmentModel } from '../segments/models.js';
|
|
3
3
|
|
|
4
4
|
export class ProjectModel {
|
|
5
5
|
id: number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { buildOrganizationModel } from '../organisations/util';
|
|
2
|
-
import { SegmentModel } from '../segments/models';
|
|
3
|
-
import { buildSegmentModel } from '../segments/util';
|
|
4
|
-
import { ProjectModel } from './models';
|
|
1
|
+
import { buildOrganizationModel } from '../organisations/util.js';
|
|
2
|
+
import { SegmentModel } from '../segments/models.js';
|
|
3
|
+
import { buildSegmentModel } from '../segments/util.js';
|
|
4
|
+
import { ProjectModel } from './models.js';
|
|
5
5
|
|
|
6
6
|
export function buildProjectModel(projectJSON: any): ProjectModel {
|
|
7
7
|
const segments: SegmentModel[] = projectJSON['segments']
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { EnvironmentModel } from '../environments/models';
|
|
2
|
-
import { IdentityModel } from '../identities/models';
|
|
3
|
-
import { TraitModel } from '../identities/traits/models';
|
|
4
|
-
import { getHashedPercentateForObjIds } from '../utils/hashing';
|
|
5
|
-
import { PERCENTAGE_SPLIT, IS_SET, IS_NOT_SET } from './constants';
|
|
6
|
-
import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models';
|
|
1
|
+
import { EnvironmentModel } from '../environments/models.js';
|
|
2
|
+
import { IdentityModel } from '../identities/models.js';
|
|
3
|
+
import { TraitModel } from '../identities/traits/models.js';
|
|
4
|
+
import { getHashedPercentateForObjIds } from '../utils/hashing/index.js';
|
|
5
|
+
import { PERCENTAGE_SPLIT, IS_SET, IS_NOT_SET } from './constants.js';
|
|
6
|
+
import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models.js';
|
|
7
7
|
|
|
8
8
|
export function getIdentitySegments(
|
|
9
9
|
environment: EnvironmentModel,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
2
|
|
|
3
|
-
import { FeatureStateModel } from '../features/models';
|
|
4
|
-
import { getCastingFunction as getCastingFunction } from '../utils';
|
|
3
|
+
import { FeatureStateModel } from '../features/models.js';
|
|
4
|
+
import { getCastingFunction as getCastingFunction } from '../utils/index.js';
|
|
5
5
|
import {
|
|
6
6
|
ALL_RULE,
|
|
7
7
|
ANY_RULE,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
MODULO,
|
|
12
12
|
IN,
|
|
13
13
|
CONDITION_OPERATORS
|
|
14
|
-
} from './constants';
|
|
15
|
-
import { isSemver } from './util';
|
|
14
|
+
} from './constants.js';
|
|
15
|
+
import { isSemver } from './util.js';
|
|
16
16
|
|
|
17
17
|
export const all = (iterable: Array<any>) => iterable.filter(e => !!e).length === iterable.length;
|
|
18
18
|
export const any = (iterable: Array<any>) => iterable.filter(e => !!e).length > 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { buildFeatureStateModel } from '../features/util';
|
|
2
|
-
import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models';
|
|
1
|
+
import { buildFeatureStateModel } from '../features/util.js';
|
|
2
|
+
import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models.js';
|
|
3
3
|
|
|
4
4
|
export function buildSegmentConditionModel(segmentConditionJSON: any): SegmentConditionModel {
|
|
5
5
|
return new SegmentConditionModel(
|
|
@@ -34,4 +34,4 @@ export function isSemver(value: any) {
|
|
|
34
34
|
|
|
35
35
|
export function removeSemverSuffix(value: string) {
|
|
36
36
|
return value.replace(':semver', '');
|
|
37
|
-
}
|
|
37
|
+
}
|
package/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Flagsmith from "./sdk";
|
|
1
|
+
import Flagsmith from "./sdk/index.js";
|
|
2
2
|
|
|
3
3
|
export {
|
|
4
4
|
AnalyticsProcessor,
|
|
@@ -9,11 +9,11 @@ export {
|
|
|
9
9
|
DefaultFlag,
|
|
10
10
|
Flags,
|
|
11
11
|
default
|
|
12
|
-
} from './sdk';
|
|
12
|
+
} from './sdk/index.js';
|
|
13
13
|
|
|
14
14
|
export {
|
|
15
15
|
FlagsmithConfig
|
|
16
|
-
} from './sdk/types'
|
|
16
|
+
} from './sdk/types.js'
|
|
17
17
|
|
|
18
18
|
export {
|
|
19
19
|
EnvironmentModel,
|
|
@@ -22,6 +22,6 @@ export {
|
|
|
22
22
|
TraitModel,
|
|
23
23
|
SegmentModel,
|
|
24
24
|
OrganisationModel
|
|
25
|
-
} from './flagsmith-engine';
|
|
25
|
+
} from './flagsmith-engine/index.js';
|
|
26
26
|
|
|
27
27
|
module.exports = Flagsmith;
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flagsmith-nodejs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-beta.1",
|
|
4
4
|
"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.",
|
|
5
|
-
"main": "build/index.js",
|
|
5
|
+
"main": "./build/cjs/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=18"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
"import": "./build/esm/index.js",
|
|
12
|
+
"require": "./build/cjs/index.js"
|
|
13
|
+
},
|
|
6
14
|
"repository": {
|
|
7
15
|
"type": "git",
|
|
8
16
|
"url": "https://github.com/Flagsmith/flagsmith-nodejs-client"
|
|
@@ -42,10 +50,11 @@
|
|
|
42
50
|
"license": "MIT",
|
|
43
51
|
"scripts": {
|
|
44
52
|
"lint": "prettier --write .",
|
|
45
|
-
"test": "
|
|
46
|
-
"test:watch": "
|
|
47
|
-
"test:debug": "
|
|
48
|
-
"
|
|
53
|
+
"test": "vitest --coverage --run",
|
|
54
|
+
"test:watch": "vitest",
|
|
55
|
+
"test:debug": "vitest --inspect-brk --no-file-parallelism --coverage",
|
|
56
|
+
"prebuild": "rm -rf ./build",
|
|
57
|
+
"build": "tsc -b tsconfig.cjs.json tsconfig.esm.json && echo '{\"type\": \"commonjs\"}'> build/cjs/package.json",
|
|
49
58
|
"deploy": "npm i && npm run build && npm publish",
|
|
50
59
|
"deploy:beta": "npm i && npm run build && npm publish --tag beta",
|
|
51
60
|
"prepare": "husky install"
|
|
@@ -53,22 +62,25 @@
|
|
|
53
62
|
"dependencies": {
|
|
54
63
|
"big-integer": "^1.6.51",
|
|
55
64
|
"md5": "^2.3.0",
|
|
56
|
-
"node-fetch": "^2.1.2",
|
|
57
65
|
"pino": "^8.8.0",
|
|
58
66
|
"semver": "^7.3.7",
|
|
67
|
+
"undici-types": "^6.19.8",
|
|
59
68
|
"uuid": "^8.3.2"
|
|
60
69
|
},
|
|
61
70
|
"devDependencies": {
|
|
62
71
|
"@types/jest": "^27.4.1",
|
|
63
72
|
"@types/md5": "^2.3.2",
|
|
64
|
-
"@types/node
|
|
73
|
+
"@types/node": "^20.16.10",
|
|
65
74
|
"@types/semver": "^7.3.9",
|
|
66
75
|
"@types/uuid": "^8.3.4",
|
|
76
|
+
"@vitest/coverage-v8": "^2.1.2",
|
|
67
77
|
"esbuild": "^0.14.25",
|
|
68
78
|
"husky": "^7.0.4",
|
|
69
79
|
"jest": "^27.5.1",
|
|
70
80
|
"prettier": "^2.2.1",
|
|
71
81
|
"ts-jest": "^27.1.3",
|
|
72
|
-
"typescript": "^4.
|
|
82
|
+
"typescript": "^4.9.5",
|
|
83
|
+
"undici": "^6.19.8",
|
|
84
|
+
"vitest": "^2.1.2"
|
|
73
85
|
}
|
|
74
86
|
}
|
package/sdk/analytics.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { pino, Logger } from 'pino';
|
|
2
|
+
import { Fetch } from "./types.js";
|
|
3
3
|
|
|
4
4
|
const ANALYTICS_ENDPOINT = 'analytics/flags/';
|
|
5
5
|
|
|
@@ -14,6 +14,7 @@ export class AnalyticsProcessor {
|
|
|
14
14
|
private requestTimeoutMs: number = 3000;
|
|
15
15
|
private logger: Logger;
|
|
16
16
|
private currentFlush: ReturnType<typeof fetch> | undefined;
|
|
17
|
+
private customFetch: Fetch;
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* AnalyticsProcessor is used to track how often individual Flags are evaluated within
|
|
@@ -24,13 +25,14 @@ export class AnalyticsProcessor {
|
|
|
24
25
|
* @param data.requestTimeoutMs used to tell requests to stop waiting for a response after a
|
|
25
26
|
given number of milliseconds
|
|
26
27
|
*/
|
|
27
|
-
constructor(data: { environmentKey: string; baseApiUrl: string; requestTimeoutMs?: number, logger?: Logger }) {
|
|
28
|
+
constructor(data: { environmentKey: string; baseApiUrl: string; requestTimeoutMs?: number, logger?: Logger, fetch?: Fetch }) {
|
|
28
29
|
this.analyticsEndpoint = data.baseApiUrl + ANALYTICS_ENDPOINT;
|
|
29
30
|
this.environmentKey = data.environmentKey;
|
|
30
31
|
this.lastFlushed = Date.now();
|
|
31
32
|
this.analyticsData = {};
|
|
32
33
|
this.requestTimeoutMs = data.requestTimeoutMs || this.requestTimeoutMs;
|
|
33
34
|
this.logger = data.logger || pino();
|
|
35
|
+
this.customFetch = data.fetch ?? fetch;
|
|
34
36
|
}
|
|
35
37
|
/**
|
|
36
38
|
* Sends all the collected data to the api asynchronously and resets the timer
|
|
@@ -41,10 +43,10 @@ export class AnalyticsProcessor {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
try {
|
|
44
|
-
this.currentFlush =
|
|
46
|
+
this.currentFlush = this.customFetch(this.analyticsEndpoint, {
|
|
45
47
|
method: 'POST',
|
|
46
48
|
body: JSON.stringify(this.analyticsData),
|
|
47
|
-
|
|
49
|
+
signal: AbortSignal.timeout(this.requestTimeoutMs),
|
|
48
50
|
headers: {
|
|
49
51
|
'Content-Type': 'application/json',
|
|
50
52
|
'X-Environment-Key': this.environmentKey
|
package/sdk/index.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine';
|
|
3
|
-
import { EnvironmentModel } from '../flagsmith-engine/
|
|
4
|
-
import { buildEnvironmentModel } from '../flagsmith-engine/environments/util';
|
|
5
|
-
import { IdentityModel } from '../flagsmith-engine/
|
|
6
|
-
import { TraitModel } from '../flagsmith-engine/
|
|
7
|
-
|
|
8
|
-
import { AnalyticsProcessor } from './analytics';
|
|
9
|
-
import { BaseOfflineHandler } from './offline_handlers';
|
|
10
|
-
import { FlagsmithAPIError, FlagsmithClientError } from './errors';
|
|
11
|
-
|
|
12
|
-
import { DefaultFlag, Flags } from './models';
|
|
13
|
-
import { EnvironmentDataPollingManager } from './polling_manager';
|
|
14
|
-
import { generateIdentitiesData, retryFetch } from './utils';
|
|
15
|
-
import { SegmentModel } from '../flagsmith-engine/
|
|
16
|
-
import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators';
|
|
17
|
-
import { FlagsmithCache, FlagsmithConfig } from './types';
|
|
18
|
-
import pino,
|
|
19
|
-
|
|
20
|
-
export { AnalyticsProcessor } from './analytics';
|
|
21
|
-
export { FlagsmithAPIError, FlagsmithClientError } from './errors';
|
|
22
|
-
|
|
23
|
-
export { DefaultFlag, Flags } from './models';
|
|
24
|
-
export { EnvironmentDataPollingManager } from './polling_manager';
|
|
25
|
-
export { FlagsmithCache, FlagsmithConfig } from './types';
|
|
1
|
+
import { Dispatcher } from 'undici-types';
|
|
2
|
+
import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine/index.js';
|
|
3
|
+
import { EnvironmentModel } from '../flagsmith-engine/index.js';
|
|
4
|
+
import { buildEnvironmentModel } from '../flagsmith-engine/environments/util.js';
|
|
5
|
+
import { IdentityModel } from '../flagsmith-engine/index.js';
|
|
6
|
+
import { TraitModel } from '../flagsmith-engine/index.js';
|
|
7
|
+
|
|
8
|
+
import { AnalyticsProcessor } from './analytics.js';
|
|
9
|
+
import { BaseOfflineHandler } from './offline_handlers.js';
|
|
10
|
+
import { FlagsmithAPIError, FlagsmithClientError } from './errors.js';
|
|
11
|
+
|
|
12
|
+
import { DefaultFlag, Flags } from './models.js';
|
|
13
|
+
import { EnvironmentDataPollingManager } from './polling_manager.js';
|
|
14
|
+
import { generateIdentitiesData, retryFetch } from './utils.js';
|
|
15
|
+
import { SegmentModel } from '../flagsmith-engine/index.js';
|
|
16
|
+
import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators.js';
|
|
17
|
+
import { Fetch, FlagsmithCache, FlagsmithConfig, FlagsmithTraitValue, ITraitConfig } from './types.js';
|
|
18
|
+
import { pino, Logger } from 'pino';
|
|
19
|
+
|
|
20
|
+
export { AnalyticsProcessor } from './analytics.js';
|
|
21
|
+
export { FlagsmithAPIError, FlagsmithClientError } from './errors.js';
|
|
22
|
+
|
|
23
|
+
export { DefaultFlag, Flags } from './models.js';
|
|
24
|
+
export { EnvironmentDataPollingManager } from './polling_manager.js';
|
|
25
|
+
export { FlagsmithCache, FlagsmithConfig } from './types.js';
|
|
26
26
|
|
|
27
27
|
const DEFAULT_API_URL = 'https://edge.api.flagsmith.com/api/v1/';
|
|
28
28
|
const DEFAULT_REQUEST_TIMEOUT_SECONDS = 10;
|
|
@@ -31,7 +31,7 @@ export class Flagsmith {
|
|
|
31
31
|
environmentKey?: string = undefined;
|
|
32
32
|
apiUrl?: string = undefined;
|
|
33
33
|
customHeaders?: { [key: string]: any };
|
|
34
|
-
agent
|
|
34
|
+
agent?: Dispatcher;
|
|
35
35
|
requestTimeoutMs?: number;
|
|
36
36
|
enableLocalEvaluation?: boolean = false;
|
|
37
37
|
environmentRefreshIntervalSeconds: number = 60;
|
|
@@ -39,7 +39,6 @@ export class Flagsmith {
|
|
|
39
39
|
enableAnalytics: boolean = false;
|
|
40
40
|
defaultFlagHandler?: (featureName: string) => DefaultFlag;
|
|
41
41
|
|
|
42
|
-
|
|
43
42
|
environmentFlagsUrl?: string;
|
|
44
43
|
identitiesUrl?: string;
|
|
45
44
|
environmentUrl?: string;
|
|
@@ -55,6 +54,7 @@ export class Flagsmith {
|
|
|
55
54
|
private onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void;
|
|
56
55
|
private analyticsProcessor?: AnalyticsProcessor;
|
|
57
56
|
private logger: Logger;
|
|
57
|
+
private customFetch: Fetch;
|
|
58
58
|
/**
|
|
59
59
|
* A Flagsmith client.
|
|
60
60
|
*
|
|
@@ -98,6 +98,7 @@ export class Flagsmith {
|
|
|
98
98
|
// }
|
|
99
99
|
|
|
100
100
|
this.agent = data.agent;
|
|
101
|
+
this.customFetch = data.fetch ?? fetch;
|
|
101
102
|
this.environmentKey = data.environmentKey;
|
|
102
103
|
this.apiUrl = data.apiUrl || this.apiUrl;
|
|
103
104
|
this.customHeaders = data.customHeaders;
|
|
@@ -168,11 +169,11 @@ export class Flagsmith {
|
|
|
168
169
|
|
|
169
170
|
this.analyticsProcessor = data.enableAnalytics
|
|
170
171
|
? new AnalyticsProcessor({
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
environmentKey: this.environmentKey,
|
|
173
|
+
baseApiUrl: this.apiUrl,
|
|
174
|
+
requestTimeoutMs: this.requestTimeoutMs,
|
|
175
|
+
logger: this.logger
|
|
176
|
+
})
|
|
176
177
|
: undefined;
|
|
177
178
|
}
|
|
178
179
|
}
|
|
@@ -207,11 +208,15 @@ export class Flagsmith {
|
|
|
207
208
|
*
|
|
208
209
|
* @param {string} identifier a unique identifier for the identity in the current
|
|
209
210
|
environment, e.g. email address, username, uuid
|
|
210
|
-
* @param {{[key:string]:any}} traits? a dictionary of traits to add / update on the identity in
|
|
211
|
-
Flagsmith, e.g. {"num_orders": 10}
|
|
211
|
+
* @param {{[key:string]:any | ITraitConfig}} traits? a dictionary of traits to add / update on the identity in
|
|
212
|
+
Flagsmith, e.g. {"num_orders": 10} or {age: {value: 30, transient: true}}
|
|
212
213
|
* @returns Flags object holding all the flags for the given identity.
|
|
213
214
|
*/
|
|
214
|
-
async getIdentityFlags(
|
|
215
|
+
async getIdentityFlags(
|
|
216
|
+
identifier: string,
|
|
217
|
+
traits?: { [key: string]: FlagsmithTraitValue | ITraitConfig },
|
|
218
|
+
transient: boolean = false
|
|
219
|
+
): Promise<Flags> {
|
|
215
220
|
if (!identifier) {
|
|
216
221
|
throw new Error('`identifier` argument is missing or invalid.');
|
|
217
222
|
}
|
|
@@ -232,7 +237,7 @@ export class Flagsmith {
|
|
|
232
237
|
return this.getIdentityFlagsFromDocument(identifier, traits || {});
|
|
233
238
|
}
|
|
234
239
|
|
|
235
|
-
return this.getIdentityFlagsFromApi(identifier, traits);
|
|
240
|
+
return this.getIdentityFlagsFromApi(identifier, traits, transient);
|
|
236
241
|
}
|
|
237
242
|
|
|
238
243
|
/**
|
|
@@ -293,8 +298,11 @@ export class Flagsmith {
|
|
|
293
298
|
}
|
|
294
299
|
if (this.environment.identityOverrides?.length) {
|
|
295
300
|
this.identitiesWithOverridesByIdentifier = new Map<string, IdentityModel>(
|
|
296
|
-
this.environment.identityOverrides.map(identity => [
|
|
297
|
-
|
|
301
|
+
this.environment.identityOverrides.map(identity => [
|
|
302
|
+
identity.identifier,
|
|
303
|
+
identity
|
|
304
|
+
])
|
|
305
|
+
);
|
|
298
306
|
}
|
|
299
307
|
if (this.onEnvironmentChange) {
|
|
300
308
|
this.onEnvironmentChange(null, this.environment);
|
|
@@ -329,13 +337,14 @@ export class Flagsmith {
|
|
|
329
337
|
const data = await retryFetch(
|
|
330
338
|
url,
|
|
331
339
|
{
|
|
332
|
-
|
|
340
|
+
dispatcher: this.agent,
|
|
333
341
|
method: method,
|
|
334
342
|
body: JSON.stringify(body),
|
|
335
343
|
headers: headers
|
|
336
344
|
},
|
|
337
345
|
this.retries,
|
|
338
|
-
this.requestTimeoutMs
|
|
346
|
+
this.requestTimeoutMs,
|
|
347
|
+
this.customFetch,
|
|
339
348
|
);
|
|
340
349
|
|
|
341
350
|
if (data.status !== 200) {
|
|
@@ -367,7 +376,6 @@ export class Flagsmith {
|
|
|
367
376
|
defaultFlagHandler: this.defaultFlagHandler
|
|
368
377
|
});
|
|
369
378
|
if (!!this.cache) {
|
|
370
|
-
// @ts-ignore node-cache types are incorrect, ttl should be optional
|
|
371
379
|
await this.cache.set('flags', flags);
|
|
372
380
|
}
|
|
373
381
|
return flags;
|
|
@@ -395,7 +403,6 @@ export class Flagsmith {
|
|
|
395
403
|
});
|
|
396
404
|
|
|
397
405
|
if (!!this.cache) {
|
|
398
|
-
// @ts-ignore node-cache types are incorrect, ttl should be optional
|
|
399
406
|
await this.cache.set(`flags-${identifier}`, flags);
|
|
400
407
|
}
|
|
401
408
|
|
|
@@ -414,7 +421,6 @@ export class Flagsmith {
|
|
|
414
421
|
defaultFlagHandler: this.defaultFlagHandler
|
|
415
422
|
});
|
|
416
423
|
if (!!this.cache) {
|
|
417
|
-
// @ts-ignore node-cache types are incorrect, ttl should be optional
|
|
418
424
|
await this.cache.set('flags', flags);
|
|
419
425
|
}
|
|
420
426
|
return flags;
|
|
@@ -433,12 +439,16 @@ export class Flagsmith {
|
|
|
433
439
|
}
|
|
434
440
|
}
|
|
435
441
|
|
|
436
|
-
private async getIdentityFlagsFromApi(
|
|
442
|
+
private async getIdentityFlagsFromApi(
|
|
443
|
+
identifier: string,
|
|
444
|
+
traits: { [key: string]: FlagsmithTraitValue | ITraitConfig },
|
|
445
|
+
transient: boolean = false
|
|
446
|
+
) {
|
|
437
447
|
if (!this.identitiesUrl) {
|
|
438
448
|
throw new Error('`apiUrl` argument is missing or invalid.');
|
|
439
449
|
}
|
|
440
450
|
try {
|
|
441
|
-
const data = generateIdentitiesData(identifier, traits);
|
|
451
|
+
const data = generateIdentitiesData(identifier, traits, transient);
|
|
442
452
|
const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
|
|
443
453
|
const flags = Flags.fromAPIFlags({
|
|
444
454
|
apiFlags: jsonResponse['flags'],
|
|
@@ -446,7 +456,6 @@ export class Flagsmith {
|
|
|
446
456
|
defaultFlagHandler: this.defaultFlagHandler
|
|
447
457
|
});
|
|
448
458
|
if (!!this.cache) {
|
|
449
|
-
// @ts-ignore node-cache types are incorrect, ttl should be optional
|
|
450
459
|
await this.cache.set(`flags-${identifier}`, flags);
|
|
451
460
|
}
|
|
452
461
|
return flags;
|
package/sdk/models.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { FeatureStateModel } from '../flagsmith-engine/features/models';
|
|
2
|
-
import { AnalyticsProcessor } from './analytics';
|
|
3
|
-
import { FlagsmithClientError } from './errors';
|
|
1
|
+
import { FeatureStateModel } from '../flagsmith-engine/features/models.js';
|
|
2
|
+
import { AnalyticsProcessor } from './analytics.js';
|
|
4
3
|
|
|
5
4
|
export class BaseFlag {
|
|
6
5
|
enabled: boolean;
|
package/sdk/offline_handlers.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import { buildEnvironmentModel } from '../flagsmith-engine/environments/util';
|
|
3
|
-
import { EnvironmentModel } from '../flagsmith-engine/environments/models';
|
|
2
|
+
import { buildEnvironmentModel } from '../flagsmith-engine/environments/util.js';
|
|
3
|
+
import { EnvironmentModel } from '../flagsmith-engine/environments/models.js';
|
|
4
4
|
|
|
5
5
|
export class BaseOfflineHandler {
|
|
6
6
|
getEnvironment() : EnvironmentModel {
|