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.
Files changed (193) hide show
  1. package/.github/workflows/publish.yml +2 -2
  2. package/.github/workflows/pull_request.yaml +7 -14
  3. package/build/{flagsmith-engine → cjs/flagsmith-engine}/environments/models.d.ts +3 -3
  4. package/build/{flagsmith-engine → cjs/flagsmith-engine}/environments/models.js +20 -13
  5. package/build/{flagsmith-engine → cjs/flagsmith-engine}/environments/util.d.ts +1 -1
  6. package/build/cjs/flagsmith-engine/environments/util.js +23 -0
  7. package/build/cjs/flagsmith-engine/features/models.js +118 -0
  8. package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/util.d.ts +1 -1
  9. package/build/cjs/flagsmith-engine/features/util.js +27 -0
  10. package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/models.d.ts +2 -2
  11. package/build/cjs/flagsmith-engine/identities/models.js +48 -0
  12. package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/traits/models.js +5 -4
  13. package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/util.d.ts +2 -2
  14. package/build/cjs/flagsmith-engine/identities/util.js +22 -0
  15. package/build/cjs/flagsmith-engine/index.d.ts +14 -0
  16. package/build/cjs/flagsmith-engine/index.js +75 -0
  17. package/build/cjs/flagsmith-engine/organisations/models.js +21 -0
  18. package/build/{flagsmith-engine → cjs/flagsmith-engine}/organisations/util.d.ts +1 -1
  19. package/build/cjs/flagsmith-engine/organisations/util.js +8 -0
  20. package/build/{flagsmith-engine → cjs/flagsmith-engine}/projects/models.d.ts +2 -2
  21. package/build/{flagsmith-engine → cjs/flagsmith-engine}/projects/models.js +8 -5
  22. package/build/{flagsmith-engine → cjs/flagsmith-engine}/projects/util.d.ts +1 -1
  23. package/build/cjs/flagsmith-engine/projects/util.js +15 -0
  24. package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/evaluators.d.ts +4 -4
  25. package/build/cjs/flagsmith-engine/segments/evaluators.js +37 -0
  26. package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/models.d.ts +1 -1
  27. package/build/cjs/flagsmith-engine/segments/models.js +111 -0
  28. package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/util.d.ts +1 -1
  29. package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/util.js +9 -11
  30. package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/collections.d.ts +1 -1
  31. package/build/cjs/flagsmith-engine/utils/collections.js +6 -0
  32. package/build/cjs/flagsmith-engine/utils/errors.js +6 -0
  33. package/build/cjs/flagsmith-engine/utils/hashing/index.js +29 -0
  34. package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/index.js +5 -5
  35. package/build/{index.d.ts → cjs/index.d.ts} +3 -3
  36. package/build/cjs/index.js +18 -0
  37. package/build/cjs/package.json +1 -0
  38. package/build/{sdk → cjs/sdk}/analytics.d.ts +3 -0
  39. package/build/cjs/sdk/analytics.js +73 -0
  40. package/build/cjs/sdk/errors.js +9 -0
  41. package/build/{sdk → cjs/sdk}/index.d.ts +19 -18
  42. package/build/cjs/sdk/index.js +400 -0
  43. package/build/{sdk → cjs/sdk}/models.d.ts +2 -2
  44. package/build/cjs/sdk/models.js +101 -0
  45. package/build/{sdk → cjs/sdk}/offline_handlers.d.ts +1 -1
  46. package/build/cjs/sdk/offline_handlers.js +23 -0
  47. package/build/{sdk → cjs/sdk}/polling_manager.d.ts +1 -1
  48. package/build/cjs/sdk/polling_manager.js +29 -0
  49. package/build/{sdk → cjs/sdk}/types.d.ts +15 -7
  50. package/build/cjs/sdk/utils.d.ts +36 -0
  51. package/build/cjs/sdk/utils.js +63 -0
  52. package/build/esm/flagsmith-engine/environments/models.d.ts +22 -0
  53. package/build/esm/flagsmith-engine/environments/models.js +32 -0
  54. package/build/esm/flagsmith-engine/environments/util.d.ts +3 -0
  55. package/build/esm/flagsmith-engine/environments/util.js +18 -0
  56. package/build/esm/flagsmith-engine/features/constants.d.ts +4 -0
  57. package/build/esm/flagsmith-engine/features/constants.js +4 -0
  58. package/build/esm/flagsmith-engine/features/models.d.ts +37 -0
  59. package/build/esm/flagsmith-engine/features/models.js +110 -0
  60. package/build/esm/flagsmith-engine/features/util.d.ts +4 -0
  61. package/build/esm/flagsmith-engine/features/util.js +21 -0
  62. package/build/esm/flagsmith-engine/identities/models.d.ts +15 -0
  63. package/build/esm/flagsmith-engine/identities/models.js +44 -0
  64. package/build/esm/flagsmith-engine/identities/traits/models.d.ts +5 -0
  65. package/build/esm/flagsmith-engine/identities/traits/models.js +8 -0
  66. package/build/esm/flagsmith-engine/identities/util.d.ts +4 -0
  67. package/build/esm/flagsmith-engine/identities/util.js +17 -0
  68. package/build/esm/flagsmith-engine/index.d.ts +14 -0
  69. package/build/esm/flagsmith-engine/index.js +62 -0
  70. package/build/esm/flagsmith-engine/organisations/models.d.ts +9 -0
  71. package/build/esm/flagsmith-engine/organisations/models.js +17 -0
  72. package/build/esm/flagsmith-engine/organisations/util.d.ts +2 -0
  73. package/build/esm/flagsmith-engine/organisations/util.js +4 -0
  74. package/build/esm/flagsmith-engine/projects/models.d.ts +10 -0
  75. package/build/esm/flagsmith-engine/projects/models.js +13 -0
  76. package/build/esm/flagsmith-engine/projects/util.d.ts +2 -0
  77. package/build/esm/flagsmith-engine/projects/util.js +11 -0
  78. package/build/esm/flagsmith-engine/segments/constants.d.ts +34 -0
  79. package/build/esm/flagsmith-engine/segments/constants.js +36 -0
  80. package/build/esm/flagsmith-engine/segments/evaluators.d.ts +7 -0
  81. package/build/esm/flagsmith-engine/segments/evaluators.js +31 -0
  82. package/build/esm/flagsmith-engine/segments/models.d.ts +37 -0
  83. package/build/esm/flagsmith-engine/segments/models.js +102 -0
  84. package/build/esm/flagsmith-engine/segments/util.d.ts +6 -0
  85. package/build/esm/flagsmith-engine/segments/util.js +23 -0
  86. package/build/esm/flagsmith-engine/utils/collections.d.ts +3 -0
  87. package/build/esm/flagsmith-engine/utils/collections.js +2 -0
  88. package/build/esm/flagsmith-engine/utils/errors.d.ts +2 -0
  89. package/build/esm/flagsmith-engine/utils/errors.js +2 -0
  90. package/build/esm/flagsmith-engine/utils/hashing/index.d.ts +9 -0
  91. package/build/esm/flagsmith-engine/utils/hashing/index.js +25 -0
  92. package/build/esm/flagsmith-engine/utils/index.d.ts +1 -0
  93. package/build/esm/flagsmith-engine/utils/index.js +13 -0
  94. package/build/esm/index.d.ts +3 -0
  95. package/build/esm/index.js +2 -0
  96. package/build/esm/sdk/analytics.d.ts +35 -0
  97. package/build/esm/sdk/analytics.js +69 -0
  98. package/build/esm/sdk/errors.d.ts +4 -0
  99. package/build/esm/sdk/errors.js +4 -0
  100. package/build/esm/sdk/index.d.ts +131 -0
  101. package/build/esm/sdk/index.js +390 -0
  102. package/build/esm/sdk/models.d.ts +55 -0
  103. package/build/esm/sdk/models.js +94 -0
  104. package/build/esm/sdk/offline_handlers.d.ts +9 -0
  105. package/build/esm/sdk/offline_handlers.js +18 -0
  106. package/build/esm/sdk/polling_manager.d.ts +9 -0
  107. package/build/esm/sdk/polling_manager.js +25 -0
  108. package/build/esm/sdk/types.d.ts +38 -0
  109. package/build/esm/sdk/types.js +1 -0
  110. package/build/esm/sdk/utils.d.ts +36 -0
  111. package/build/esm/sdk/utils.js +56 -0
  112. package/flagsmith-engine/environments/models.ts +3 -3
  113. package/flagsmith-engine/environments/util.ts +4 -4
  114. package/flagsmith-engine/features/models.ts +2 -2
  115. package/flagsmith-engine/features/util.ts +1 -1
  116. package/flagsmith-engine/identities/models.ts +4 -5
  117. package/flagsmith-engine/identities/traits/models.ts +0 -1
  118. package/flagsmith-engine/identities/util.ts +4 -4
  119. package/flagsmith-engine/index.ts +13 -13
  120. package/flagsmith-engine/organisations/util.ts +1 -1
  121. package/flagsmith-engine/projects/models.ts +2 -2
  122. package/flagsmith-engine/projects/util.ts +4 -4
  123. package/flagsmith-engine/segments/evaluators.ts +6 -6
  124. package/flagsmith-engine/segments/models.ts +5 -5
  125. package/flagsmith-engine/segments/util.ts +3 -3
  126. package/flagsmith-engine/utils/collections.ts +1 -1
  127. package/flagsmith-engine/utils/hashing/index.ts +5 -29
  128. package/flagsmith-engine/utils/index.ts +1 -1
  129. package/index.ts +4 -8
  130. package/package.json +21 -16
  131. package/sdk/analytics.ts +7 -5
  132. package/sdk/index.ts +55 -46
  133. package/sdk/models.ts +2 -3
  134. package/sdk/offline_handlers.ts +2 -2
  135. package/sdk/polling_manager.ts +2 -3
  136. package/sdk/types.ts +35 -24
  137. package/sdk/utils.ts +49 -37
  138. package/tests/engine/e2e/engine.test.ts +8 -11
  139. package/tests/engine/unit/engine.test.ts +5 -5
  140. package/tests/engine/unit/segments/segment_evaluators.test.ts +9 -9
  141. package/tests/engine/unit/utils/utils.test.ts +2 -2
  142. package/tests/sdk/analytics.test.ts +8 -13
  143. package/tests/sdk/data/identity-with-transient-traits.json +41 -0
  144. package/tests/sdk/data/transient-identity.json +29 -0
  145. package/tests/sdk/flagsmith-cache.test.ts +16 -32
  146. package/tests/sdk/flagsmith-environment-flags.test.ts +21 -36
  147. package/tests/sdk/flagsmith-identity-flags.test.ts +83 -32
  148. package/tests/sdk/flagsmith.test.ts +67 -99
  149. package/tests/sdk/offline-handlers.test.ts +5 -6
  150. package/tests/sdk/polling.test.ts +6 -8
  151. package/tests/sdk/utils.ts +19 -15
  152. package/tsconfig.cjs.json +7 -0
  153. package/tsconfig.esm.json +7 -0
  154. package/tsconfig.json +8 -4
  155. package/vitest.config.ts +17 -0
  156. package/build/flagsmith-engine/environments/util.js +0 -27
  157. package/build/flagsmith-engine/features/models.js +0 -132
  158. package/build/flagsmith-engine/features/util.js +0 -27
  159. package/build/flagsmith-engine/identities/models.js +0 -113
  160. package/build/flagsmith-engine/identities/util.js +0 -46
  161. package/build/flagsmith-engine/index.d.ts +0 -14
  162. package/build/flagsmith-engine/index.js +0 -127
  163. package/build/flagsmith-engine/organisations/models.js +0 -21
  164. package/build/flagsmith-engine/organisations/util.js +0 -8
  165. package/build/flagsmith-engine/projects/util.js +0 -15
  166. package/build/flagsmith-engine/segments/evaluators.js +0 -45
  167. package/build/flagsmith-engine/segments/models.js +0 -147
  168. package/build/flagsmith-engine/utils/collections.js +0 -26
  169. package/build/flagsmith-engine/utils/errors.js +0 -26
  170. package/build/flagsmith-engine/utils/hashing/index.js +0 -60
  171. package/build/index.js +0 -23
  172. package/build/sdk/analytics.js +0 -120
  173. package/build/sdk/errors.js +0 -34
  174. package/build/sdk/index.js +0 -594
  175. package/build/sdk/models.js +0 -149
  176. package/build/sdk/offline_handlers.js +0 -66
  177. package/build/sdk/polling_manager.js +0 -72
  178. package/build/sdk/utils.d.ts +0 -12
  179. package/build/sdk/utils.js +0 -107
  180. package/jest.config.js +0 -5
  181. package/tests/index.js +0 -0
  182. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/constants.d.ts +0 -0
  183. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/constants.js +0 -0
  184. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/features/models.d.ts +0 -0
  185. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/identities/traits/models.d.ts +0 -0
  186. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/organisations/models.d.ts +0 -0
  187. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/constants.d.ts +0 -0
  188. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/segments/constants.js +0 -0
  189. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/errors.d.ts +0 -0
  190. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/hashing/index.d.ts +0 -0
  191. /package/build/{flagsmith-engine → cjs/flagsmith-engine}/utils/index.d.ts +0 -0
  192. /package/build/{sdk → cjs/sdk}/errors.d.ts +0 -0
  193. /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 { v4 as uuidv4 } from 'uuid';
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 { FeatureStateModel } from '../features/models';
2
- import { IdentityFeaturesList } from '../utils/collections';
3
- import { TraitModel } from './traits/models';
1
+ import { IdentityFeaturesList } from '../utils/collections.js';
2
+ import { TraitModel } from './traits/models.js';
4
3
 
5
- const { v4: uuidv4 } = require('uuid');
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,6 @@
1
1
  export class TraitModel {
2
2
  traitKey: string;
3
3
  traitValue: any;
4
-
5
4
  constructor(key: string, value: any) {
6
5
  this.traitKey = key;
7
6
  this.traitValue = value;
@@ -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,4 +1,4 @@
1
- import { OrganisationModel } from './models';
1
+ import { OrganisationModel } from './models.js';
2
2
 
3
3
  export function buildOrganizationModel(organizationJSON: any): OrganisationModel {
4
4
  return new OrganisationModel(
@@ -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,3 +1,3 @@
1
- import { FeatureStateModel } from '../features/models';
1
+ import { FeatureStateModel } from '../features/models.js';
2
2
 
3
3
  export class IdentityFeaturesList extends Array<FeatureStateModel> {}
@@ -1,35 +1,11 @@
1
- import md5 from 'md5';
2
- import bigInt from 'big-integer';
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 = bigInt(h2d(hashedValue));
45
- const value = (hashedInt.mod(9999).toJSNumber() / 9998) * 100;
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 */
@@ -1,4 +1,4 @@
1
- import { removeSemverSuffix } from "../segments/util";
1
+ import { removeSemverSuffix } from "../segments/util.js";
2
2
 
3
3
  export function getCastingFunction(traitType: 'boolean' | 'string' | 'number' | 'semver' | any): CallableFunction {
4
4
  switch (traitType) {
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
- default
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.3.3",
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": "jest --coverage --coverageReporters='text'",
46
- "test:watch": "jest --coverage --watch --coverageReporters='text'",
47
- "test:debug": "node --inspect-brk node_modules/.bin/jest --coverage --watch --coverageReporters='text'",
48
- "build": "tsc",
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
- "uuid": "^8.3.2"
65
+ "undici-types": "^6.19.8"
60
66
  },
61
67
  "devDependencies": {
62
- "@types/jest": "^27.4.1",
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
- "ts-jest": "^27.1.3",
72
- "typescript": "^4.6.2"
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 fetch from 'node-fetch';
2
- import pino, { Logger } from 'pino';
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 = fetch(this.analyticsEndpoint, {
46
+ this.currentFlush = this.customFetch(this.analyticsEndpoint, {
45
47
  method: 'POST',
46
48
  body: JSON.stringify(this.analyticsData),
47
- timeout: this.requestTimeoutMs,
49
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
48
50
  headers: {
49
51
  'Content-Type': 'application/json',
50
52
  'X-Environment-Key': this.environmentKey