flagsmith-nodejs 3.3.3 → 4.0.0
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 +7 -14
- 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 +111 -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/cjs/flagsmith-engine/utils/hashing/index.js +29 -0
- 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/cjs/index.js +18 -0
- 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 +23 -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 +25 -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 +2 -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 +2 -2
- package/flagsmith-engine/features/util.ts +1 -1
- package/flagsmith-engine/identities/models.ts +4 -5
- 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 +5 -5
- package/flagsmith-engine/segments/util.ts +3 -3
- package/flagsmith-engine/utils/collections.ts +1 -1
- package/flagsmith-engine/utils/hashing/index.ts +5 -29
- package/flagsmith-engine/utils/index.ts +1 -1
- package/index.ts +4 -8
- package/package.json +21 -16
- 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 -37
- package/tests/engine/e2e/engine.test.ts +8 -11
- 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 +2 -2
- 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 +5 -6
- 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 +8 -4
- 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/flagsmith-engine/utils/hashing/index.js +0 -60
- package/build/index.js +0 -23
- 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 -107
- 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);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getHashedPercentateForObjIds } from '../utils/hashing';
|
|
1
|
+
import { randomUUID as uuidv4 } from "node:crypto";
|
|
2
|
+
import { getHashedPercentateForObjIds } from '../utils/hashing/index.js';
|
|
3
3
|
|
|
4
4
|
export class FeatureModel {
|
|
5
5
|
id: number;
|
|
@@ -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,8 +1,7 @@
|
|
|
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
|
+
import { randomUUID as uuidv4 } from 'node:crypto';
|
|
6
5
|
|
|
7
6
|
export class IdentityModel {
|
|
8
7
|
identifier: string;
|
|
@@ -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
|
-
import semver from 'semver';
|
|
1
|
+
import * as 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
|
+
}
|
|
@@ -1,35 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {BinaryLike, createHash} from "node:crypto";
|
|
2
|
+
|
|
3
|
+
const md5 = (data: BinaryLike) => createHash('md5').update(data).digest('hex')
|
|
3
4
|
|
|
4
5
|
const makeRepeated = (arr: Array<any>, repeats: number) =>
|
|
5
6
|
Array.from({ length: repeats }, () => arr).flat();
|
|
6
7
|
|
|
7
8
|
// https://stackoverflow.com/questions/12532871/how-to-convert-a-very-large-hex-number-to-decimal-in-javascript
|
|
8
|
-
function h2d(s: any): string {
|
|
9
|
-
function add(x: any, y: any) {
|
|
10
|
-
var c = 0,
|
|
11
|
-
r = [];
|
|
12
|
-
var x = x.split('').map(Number);
|
|
13
|
-
var y = y.split('').map(Number);
|
|
14
|
-
while (x.length || y.length) {
|
|
15
|
-
var s = (x.pop() || 0) + (y.pop() || 0) + c;
|
|
16
|
-
r.unshift(s < 10 ? s : s - 10);
|
|
17
|
-
c = s < 10 ? 0 : 1;
|
|
18
|
-
}
|
|
19
|
-
if (c) r.unshift(c);
|
|
20
|
-
return r.join('');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
var dec = '0';
|
|
24
|
-
s.split('').forEach(function (chr: any) {
|
|
25
|
-
var n = parseInt(chr, 16);
|
|
26
|
-
for (var t = 8; t; t >>= 1) {
|
|
27
|
-
dec = add(dec, dec);
|
|
28
|
-
if (n & t) dec = add(dec, '1');
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return dec;
|
|
32
|
-
}
|
|
33
9
|
/**
|
|
34
10
|
* Given a list of object ids, get a floating point number between 0 and 1 based on
|
|
35
11
|
* the hash of those ids. This should give the same value every time for any list of ids.
|
|
@@ -41,8 +17,8 @@ function h2d(s: any): string {
|
|
|
41
17
|
export function getHashedPercentateForObjIds(objectIds: Array<any>, iterations = 1): number {
|
|
42
18
|
let toHash = makeRepeated(objectIds, iterations).join(',');
|
|
43
19
|
const hashedValue = md5(toHash);
|
|
44
|
-
const hashedInt =
|
|
45
|
-
const value = (
|
|
20
|
+
const hashedInt = BigInt('0x' + hashedValue);
|
|
21
|
+
const value = (Number((hashedInt % 9999n)) / 9998.0) * 100;
|
|
46
22
|
|
|
47
23
|
// we ignore this for it's nearly impossible use case to catch
|
|
48
24
|
/* istanbul ignore next */
|
package/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import Flagsmith from "./sdk";
|
|
2
|
-
|
|
3
1
|
export {
|
|
4
2
|
AnalyticsProcessor,
|
|
5
3
|
FlagsmithAPIError,
|
|
@@ -8,12 +6,12 @@ export {
|
|
|
8
6
|
FlagsmithCache,
|
|
9
7
|
DefaultFlag,
|
|
10
8
|
Flags,
|
|
11
|
-
|
|
12
|
-
} from './sdk';
|
|
9
|
+
Flagsmith,
|
|
10
|
+
} from './sdk/index.js';
|
|
13
11
|
|
|
14
12
|
export {
|
|
15
13
|
FlagsmithConfig
|
|
16
|
-
} from './sdk/types'
|
|
14
|
+
} from './sdk/types.js'
|
|
17
15
|
|
|
18
16
|
export {
|
|
19
17
|
EnvironmentModel,
|
|
@@ -22,6 +20,4 @@ export {
|
|
|
22
20
|
TraitModel,
|
|
23
21
|
SegmentModel,
|
|
24
22
|
OrganisationModel
|
|
25
|
-
} from './flagsmith-engine';
|
|
26
|
-
|
|
27
|
-
module.exports = Flagsmith;
|
|
23
|
+
} from './flagsmith-engine/index.js';
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flagsmith-nodejs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
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,33 +50,30 @@
|
|
|
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"
|
|
52
61
|
},
|
|
53
62
|
"dependencies": {
|
|
54
|
-
"big-integer": "^1.6.51",
|
|
55
|
-
"md5": "^2.3.0",
|
|
56
|
-
"node-fetch": "^2.1.2",
|
|
57
63
|
"pino": "^8.8.0",
|
|
58
64
|
"semver": "^7.3.7",
|
|
59
|
-
"
|
|
65
|
+
"undici-types": "^6.19.8"
|
|
60
66
|
},
|
|
61
67
|
"devDependencies": {
|
|
62
|
-
"@types/
|
|
63
|
-
"@types/md5": "^2.3.2",
|
|
64
|
-
"@types/node-fetch": "^2.6.1",
|
|
68
|
+
"@types/node": "^20.16.10",
|
|
65
69
|
"@types/semver": "^7.3.9",
|
|
66
70
|
"@types/uuid": "^8.3.4",
|
|
71
|
+
"@vitest/coverage-v8": "^2.1.2",
|
|
67
72
|
"esbuild": "^0.14.25",
|
|
68
73
|
"husky": "^7.0.4",
|
|
69
|
-
"jest": "^27.5.1",
|
|
70
74
|
"prettier": "^2.2.1",
|
|
71
|
-
"
|
|
72
|
-
"
|
|
75
|
+
"typescript": "^4.9.5",
|
|
76
|
+
"undici": "^6.19.8",
|
|
77
|
+
"vitest": "^2.1.2"
|
|
73
78
|
}
|
|
74
79
|
}
|
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
|