flagsmith-nodejs 1.0.9 → 2.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.
Files changed (127) hide show
  1. package/.github/workflows/pull_request.yaml +33 -0
  2. package/.gitmodules +3 -0
  3. package/.husky/pre-commit +6 -0
  4. package/.idea/flagsmith-nodejs-client.iml +12 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/vcs.xml +6 -0
  7. package/.prettierignore +1 -0
  8. package/.prettierrc.js +9 -0
  9. package/CONTRIBUTING.md +5 -4
  10. package/{LICENCE.md → LICENCE} +5 -6
  11. package/README.md +1 -1
  12. package/build/flagsmith-engine/environments/integrations/models.d.ts +4 -0
  13. package/build/flagsmith-engine/environments/integrations/models.js +8 -0
  14. package/build/flagsmith-engine/environments/models.d.ts +25 -0
  15. package/build/flagsmith-engine/environments/models.js +40 -0
  16. package/build/flagsmith-engine/environments/util.d.ts +3 -0
  17. package/build/flagsmith-engine/environments/util.js +19 -0
  18. package/build/flagsmith-engine/features/constants.d.ts +4 -0
  19. package/build/flagsmith-engine/features/constants.js +7 -0
  20. package/build/flagsmith-engine/features/models.d.ts +32 -0
  21. package/build/flagsmith-engine/features/models.js +85 -0
  22. package/build/flagsmith-engine/features/util.d.ts +3 -0
  23. package/build/flagsmith-engine/features/util.js +20 -0
  24. package/build/flagsmith-engine/identities/models.d.ts +15 -0
  25. package/build/flagsmith-engine/identities/models.js +47 -0
  26. package/build/flagsmith-engine/identities/traits/models.d.ts +5 -0
  27. package/build/flagsmith-engine/identities/traits/models.js +12 -0
  28. package/build/flagsmith-engine/identities/util.d.ts +4 -0
  29. package/build/flagsmith-engine/identities/util.js +22 -0
  30. package/build/flagsmith-engine/index.d.ts +8 -0
  31. package/build/flagsmith-engine/index.js +60 -0
  32. package/build/flagsmith-engine/organisations/models.d.ts +9 -0
  33. package/build/flagsmith-engine/organisations/models.js +21 -0
  34. package/build/flagsmith-engine/organisations/util.d.ts +2 -0
  35. package/build/flagsmith-engine/organisations/util.js +8 -0
  36. package/build/flagsmith-engine/projects/models.d.ts +10 -0
  37. package/build/flagsmith-engine/projects/models.js +18 -0
  38. package/build/flagsmith-engine/projects/util.d.ts +2 -0
  39. package/build/flagsmith-engine/projects/util.js +15 -0
  40. package/build/flagsmith-engine/segments/constants.d.ts +26 -0
  41. package/build/flagsmith-engine/segments/constants.js +31 -0
  42. package/build/flagsmith-engine/segments/evaluators.d.ts +6 -0
  43. package/build/flagsmith-engine/segments/evaluators.js +29 -0
  44. package/build/flagsmith-engine/segments/models.d.ts +31 -0
  45. package/build/flagsmith-engine/segments/models.js +83 -0
  46. package/build/flagsmith-engine/segments/util.d.ts +4 -0
  47. package/build/flagsmith-engine/segments/util.js +23 -0
  48. package/build/flagsmith-engine/utils/collections.d.ts +4 -0
  49. package/build/flagsmith-engine/utils/collections.js +16 -0
  50. package/build/flagsmith-engine/utils/hashing/index.d.ts +1 -0
  51. package/build/flagsmith-engine/utils/hashing/index.js +56 -0
  52. package/build/flagsmith-engine/utils/index.d.ts +1 -0
  53. package/build/flagsmith-engine/utils/index.js +14 -0
  54. package/build/index.d.ts +2 -0
  55. package/build/index.js +7 -0
  56. package/build/sdk/analytics.d.ts +28 -0
  57. package/build/sdk/analytics.js +81 -0
  58. package/build/sdk/errors.d.ts +4 -0
  59. package/build/sdk/errors.js +9 -0
  60. package/build/sdk/index.d.ts +99 -0
  61. package/build/sdk/index.js +221 -0
  62. package/build/sdk/models.d.ts +55 -0
  63. package/build/sdk/models.js +102 -0
  64. package/build/sdk/polling_manager.d.ts +9 -0
  65. package/build/sdk/polling_manager.js +31 -0
  66. package/build/sdk/utils.d.ts +12 -0
  67. package/build/sdk/utils.js +45 -0
  68. package/example/README.md +8 -14
  69. package/example/package-lock.json +12 -12
  70. package/example/package.json +4 -4
  71. package/example/server/api/index.js +19 -22
  72. package/example/server/index.js +4 -9
  73. package/flagsmith-engine/environments/integrations/models.ts +4 -0
  74. package/flagsmith-engine/environments/models.ts +50 -0
  75. package/flagsmith-engine/environments/util.ts +29 -0
  76. package/flagsmith-engine/features/constants.ts +4 -0
  77. package/flagsmith-engine/features/models.ts +105 -0
  78. package/flagsmith-engine/features/util.ts +38 -0
  79. package/flagsmith-engine/identities/models.ts +60 -0
  80. package/flagsmith-engine/identities/traits/models.ts +9 -0
  81. package/flagsmith-engine/identities/util.ts +30 -0
  82. package/flagsmith-engine/index.ts +92 -0
  83. package/flagsmith-engine/organisations/models.ts +25 -0
  84. package/flagsmith-engine/organisations/util.ts +11 -0
  85. package/flagsmith-engine/projects/models.ts +23 -0
  86. package/flagsmith-engine/projects/util.ts +18 -0
  87. package/flagsmith-engine/segments/constants.ts +31 -0
  88. package/flagsmith-engine/segments/evaluators.ts +72 -0
  89. package/flagsmith-engine/segments/models.ts +103 -0
  90. package/flagsmith-engine/segments/util.ts +29 -0
  91. package/flagsmith-engine/utils/collections.ts +14 -0
  92. package/flagsmith-engine/utils/hashing/index.ts +57 -0
  93. package/flagsmith-engine/utils/index.ts +10 -0
  94. package/index.ts +3 -0
  95. package/jest.config.js +5 -0
  96. package/package.json +24 -3
  97. package/sdk/analytics.ts +88 -0
  98. package/sdk/errors.ts +2 -0
  99. package/sdk/index.ts +282 -0
  100. package/sdk/models.ts +143 -0
  101. package/sdk/polling_manager.ts +31 -0
  102. package/sdk/utils.ts +45 -0
  103. package/tests/engine/e2e/engine.test.ts +51 -0
  104. package/tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json +12393 -0
  105. package/tests/engine/engine-tests/engine-test-data/readme.md +30 -0
  106. package/tests/engine/unit/egine.test.ts +96 -0
  107. package/tests/engine/unit/environments/builder.test.ts +148 -0
  108. package/tests/engine/unit/environments/models.test.ts +49 -0
  109. package/tests/engine/unit/features/models.test.ts +72 -0
  110. package/tests/engine/unit/identities/identities_builders.test.ts +85 -0
  111. package/tests/engine/unit/identities/identities_models.test.ts +105 -0
  112. package/tests/engine/unit/organization/models.test.ts +12 -0
  113. package/tests/engine/unit/segments/segments_model.test.ts +101 -0
  114. package/tests/engine/unit/segments/util.ts +151 -0
  115. package/tests/engine/unit/utils.ts +114 -0
  116. package/tests/index.js +0 -0
  117. package/tests/sdk/analytics.test.ts +43 -0
  118. package/tests/sdk/data/environment.json +33 -0
  119. package/tests/sdk/data/flags.json +20 -0
  120. package/tests/sdk/data/identities.json +29 -0
  121. package/tests/sdk/flagsmith.test.ts +184 -0
  122. package/tests/sdk/polling.test.ts +34 -0
  123. package/tests/sdk/utils.ts +39 -0
  124. package/tsconfig.json +19 -0
  125. package/flagsmith-core.js +0 -238
  126. package/index.d.ts +0 -78
  127. package/index.js +0 -5
@@ -0,0 +1,34 @@
1
+ import { Flagsmith } from '../../sdk';
2
+ import { EnvironmentDataPollingManager } from '../../sdk/polling_manager';
3
+ import { delay } from '../../sdk/utils';
4
+ jest.mock('../../sdk');
5
+ jest.mock('node-fetch');
6
+
7
+ beforeEach(() => {
8
+ // @ts-ignore
9
+ Flagsmith.mockClear();
10
+ });
11
+
12
+ test('test_polling_manager_calls_update_environment_on_start', async () => {
13
+ const flagsmith = new Flagsmith({
14
+ environmentKey: 'key'
15
+ });
16
+
17
+ const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1);
18
+ pollingManager.start();
19
+ await delay(500);
20
+ pollingManager.stop();
21
+ expect(flagsmith.updateEnvironment).toHaveBeenCalled();
22
+ });
23
+
24
+ test('test_polling_manager_calls_update_environment_on_each_refresh', async () => {
25
+ const flagsmith = new Flagsmith({
26
+ environmentKey: 'key'
27
+ });
28
+
29
+ const pollingManager = new EnvironmentDataPollingManager(flagsmith, 0.1);
30
+ pollingManager.start();
31
+ await delay(450);
32
+ pollingManager.stop();
33
+ expect(flagsmith.updateEnvironment).toHaveBeenCalledTimes(5);
34
+ });
@@ -0,0 +1,39 @@
1
+ import { readFileSync } from 'fs';
2
+ import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util';
3
+ import { AnalyticsProcessor } from '../../sdk/analytics';
4
+ import { Flagsmith } from '../../sdk';
5
+
6
+ const DATA_DIR = __dirname + '/data/';
7
+
8
+ export function analyticsProcessor() {
9
+ return new AnalyticsProcessor({
10
+ environmentKey: 'test-key',
11
+ baseApiUrl: 'http://testUrl'
12
+ });
13
+ }
14
+
15
+ export function apiKey(): string {
16
+ return 'sometestfakekey';
17
+ }
18
+
19
+ export function flagsmith() {
20
+ return new Flagsmith({
21
+ environmentKey: apiKey()
22
+ });
23
+ }
24
+
25
+ export function environmentJSON() {
26
+ return readFileSync(DATA_DIR + 'environment.json', 'utf-8');
27
+ }
28
+
29
+ export function environmentModel(environmentJSON: any) {
30
+ return buildEnvironmentModel(environmentJSON);
31
+ }
32
+
33
+ export function flagsJSON() {
34
+ return readFileSync(DATA_DIR + 'flags.json', 'utf-8');
35
+ }
36
+
37
+ export function identitiesJSON() {
38
+ return readFileSync(DATA_DIR + 'identities.json', 'utf-8');
39
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "include": [
3
+ "./flagsmith-engine",
4
+ "./sdk",
5
+ "./index.ts"
6
+ ],
7
+ "compilerOptions": {
8
+ "outDir": "./build",
9
+ "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
10
+ /* Modules */
11
+ "module": "commonjs", /* Specify what module code is generated. */
12
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
13
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
14
+ "declaration": true,
15
+ "strict": true, /* Enable all strict type-checking options. */
16
+ "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
17
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
18
+ }
19
+ }
package/flagsmith-core.js DELETED
@@ -1,238 +0,0 @@
1
- let fetch;
2
-
3
- const FlagsmithCore = class {
4
-
5
- constructor(props) {
6
- fetch = props.fetch;
7
-
8
- this.checkFeatureEnabled = this.checkFeatureEnabled.bind(this);
9
- this.getFlags = this.getFlags.bind(this);
10
- this.getFlagsForUser = this.getFlagsForUser.bind(this);
11
- this.getUserIdentity = this.getUserIdentity.bind(this);
12
- this.getValue = this.getValue.bind(this);
13
- this.getValueFromFeatures = this.getValueFromFeatures.bind(this);
14
- this.hasFeature = this.hasFeature.bind(this);
15
- this.init = this.init.bind(this);
16
-
17
- this.getJSON = function (url, method, body) {
18
- const { environmentID } = this;
19
- const options = {
20
- method: method || 'GET',
21
- body,
22
- headers: {
23
- 'x-environment-key': environmentID
24
- }
25
- };
26
- if (method !== "GET") {
27
- options.headers['Content-Type'] = 'application/json; charset=utf-8';
28
- }
29
- return fetch(url, options)
30
- .then(res => {
31
- return res.json()
32
- .then(result => {
33
- if (res.status < 200 || res.status >= 400) {
34
- Promise.reject(new Error(result.detail))
35
- } else return result;
36
- })
37
- });
38
- };
39
- }
40
-
41
- getFlagsForUser (identity) {
42
- const { onError, api } = this;
43
-
44
- if (!identity) {
45
- onError && onError({message: 'getFlagsForUser() called without a user identity'});
46
- return Promise.reject('getFlagsForUser() called without a user identity');
47
- }
48
-
49
- const handleResponse = (res) => {
50
- // Handle server response
51
- let flags = {};
52
- res.flags.forEach(feature => {
53
- flags[feature.feature.name.toLowerCase().replace(/ /g, '_')] = {
54
- enabled: feature.enabled,
55
- value: feature.feature_state_value
56
- };
57
- });
58
- return flags;
59
- };
60
-
61
- return this.getJSON(api + 'identities/?identifier=' + identity)
62
- .then(res => {
63
- return handleResponse(res);
64
- }).catch(({ message }) => {
65
- onError && onError({ message });
66
- return Promise.reject(message);
67
- });
68
- }
69
-
70
- getUserIdentity (identity) {
71
- const { onError, api } = this;
72
-
73
- if (!identity) {
74
- onError && onError({message: 'getUserIdentity() called without a user identity'});
75
- return Promise.reject('getUserIdentity() called without a user identity');
76
- }
77
-
78
- const handleResponse = (res) => {
79
- // Handle server response
80
- let flags = {};
81
- let traits = {};
82
- res.flags.forEach(feature => {
83
- flags[feature.feature.name.toLowerCase().replace(/ /g, '_')] = {
84
- enabled: feature.enabled,
85
- value: feature.feature_state_value
86
- };
87
- });
88
- res.traits.forEach(({trait_key, trait_value}) => {
89
- traits[trait_key.toLowerCase().replace(/ /g, '_')] = trait_value;
90
- });
91
- return { flags, traits };
92
- };
93
-
94
- return this.getJSON(api + 'identities/?identifier=' + identity)
95
- .then(res => {
96
- return handleResponse(res);
97
- }).catch(({ message }) => {
98
- onError && onError({ message });
99
- return Promise.reject(message);
100
- });
101
- }
102
-
103
- getFlags() {
104
- const { onError, api } = this;
105
-
106
- const handleResponse = (res) => {
107
- // Handle server response
108
- let flags = {};
109
- res.forEach(feature => {
110
- flags[feature.feature.name.toLowerCase().replace(/ /g, '_')] = {
111
- enabled: feature.enabled,
112
- value: feature.feature_state_value
113
- };
114
- });
115
- return flags;
116
- };
117
-
118
- return this.getJSON(api + "flags/")
119
- .then(res => {
120
- return handleResponse(res);
121
- }).catch(({ message }) => {
122
- onError && onError({ message });
123
- return Promise.reject(message);
124
- });
125
- };
126
-
127
- init({
128
- environmentID,
129
- api,
130
- disableCache,
131
- onError,
132
- }) {
133
- if (!environmentID) {
134
- throw new Error('Please specify a environment id');
135
- }
136
-
137
- this.environmentID = environmentID;
138
-
139
- this.api = api || "https://api.bullet-train.io/api/v1/";
140
- this.disableCache = disableCache;
141
- this.onError = onError;
142
- }
143
-
144
- getValue (key, userId) {
145
- if (userId) {
146
- return this.getFlagsForUser(userId).then((flags) => {
147
- return this.getValueFromFeatures(key, flags);
148
- })
149
- } else {
150
- return this.getFlags().then((flags) => {
151
- return this.getValueFromFeatures(key, flags);
152
- });
153
- }
154
- }
155
-
156
- hasFeature (key, userId) {
157
- if (userId) {
158
- return this.getFlagsForUser(userId).then((flags) => {
159
- return this.checkFeatureEnabled(key, flags);
160
- })
161
- } else {
162
- return this.getFlags().then((flags) => {
163
- return this.checkFeatureEnabled(key, flags);
164
- });
165
- }
166
- }
167
-
168
- getValueFromFeatures (key, flags) {
169
- if (!flags) {
170
- return null;
171
- }
172
- const flag = flags[key];
173
- let res = null;
174
- if (flag) {
175
- res = flag.value;
176
- }
177
- //todo record check for value
178
-
179
- return res;
180
- }
181
-
182
- checkFeatureEnabled (key, flags) {
183
- if (!flags) {
184
- return false;
185
- }
186
- const flag = flags[key];
187
- let res = false;
188
- if (flag && flag.enabled) {
189
- res = true;
190
- }
191
-
192
- return res;
193
- }
194
-
195
- getTrait (identity, key) {
196
- const { onError } = this;
197
-
198
- if (!identity || !key) {
199
- onError && onError({message: `getTrait() called without a ${!identity ? 'user identity' : 'trait key'}`});
200
- return Promise.reject(`getTrait() called without a ${!identity ? 'user identity' : 'trait key'}`);
201
- }
202
-
203
- return this.getUserIdentity(identity)
204
- .then(({traits}) => traits[key])
205
- .catch(({ message }) => {
206
- onError && onError({ message });
207
- return Promise.reject(message);
208
- });
209
- }
210
-
211
- setTrait (identity, key, value) {
212
- const { onError, api } = this;
213
-
214
- if (!identity || !key) {
215
- onError && onError({message: `setTrait() called without a ${!identity ? 'user identity' : 'trait key'}`});
216
- return Promise.reject(`setTrait() called without a ${!identity ? 'user identity' : 'trait key'}`);
217
- }
218
-
219
- const body = {
220
- "identity": {
221
- "identifier": identity
222
- },
223
- "trait_key": key,
224
- "trait_value": value
225
- }
226
-
227
- return this.getJSON(`${api}traits/`, 'POST', JSON.stringify(body))
228
- .then(() => this.getUserIdentity(identity))
229
- .catch(({ message }) => {
230
- onError && onError({ message });
231
- return Promise.reject(message);
232
- });
233
- }
234
- };
235
-
236
- module.exports = function ({ fetch }) {
237
- return new FlagsmithCore({ fetch });
238
- };
package/index.d.ts DELETED
@@ -1,78 +0,0 @@
1
- declare module 'flagsmith-nodejs' {
2
- /**
3
- * Initialise the sdk against a particular environment
4
- */
5
- export function init(config: {
6
- environmentID: string
7
- onError?: Function
8
- defaultFlags?: string[]
9
- api?: string
10
- }): void
11
-
12
- /**
13
- * Get the whether a flag is enabled e.g. flagsmith.hasFeature("powerUserFeature")
14
- */
15
- export function hasFeature(key: string): Promise<boolean>
16
-
17
- /**
18
- * Get the value of a whether a flag is enabled for a user e.g. flagsmith.hasFeature("powerUserFeature", 1234)
19
- */
20
- export function hasFeature(key: string, userId: string): Promise<boolean>
21
-
22
- /**
23
- * Get the value of a particular remote config e.g. flagsmith.getValue("font_size")
24
- */
25
- export function getValue(key: string): Promise<string|number|boolean>
26
-
27
- /**
28
- * Get the value of a particular remote config for a specified user e.g. flagsmith.getValue("font_size", 1234)
29
- */
30
- export function getValue(key: string, userId: string): Promise<string|number|boolean>
31
-
32
- /**
33
- * Trigger a manual fetch of the environment features
34
- */
35
- export function getFlags(): Promise<IFlags>
36
-
37
- /**
38
- * Trigger a manual fetch of the environment features for a given user id
39
- */
40
- export function getFlagsForUser(userId: string): Promise<IFlags>
41
-
42
- /**
43
- * Trigger a manual fetch of both the environment features and users' traits for a given user id
44
- */
45
- export function getUserIdentity(userId: string): Promise<IUserIdentity>
46
-
47
- /**
48
- * Trigger a manual fetch of a specific trait for a given user id
49
- */
50
- export function getTrait(userId: string, key: string): Promise<ITraits>
51
-
52
- /**
53
- * Set a specific trait for a given user id
54
- */
55
- export function setTrait(
56
- userId: string,
57
- key: string,
58
- value: string|number|boolean
59
- ): IUserIdentity
60
-
61
- interface IFeature {
62
- enabled: boolean
63
- value?: string|number|boolean
64
- }
65
-
66
- interface IFlags {
67
- [key: string]: IFeature
68
- }
69
-
70
- interface ITraits {
71
- [key: string]: string
72
- }
73
-
74
- interface IUserIdentity {
75
- flags: IFeature
76
- traits: ITraits
77
- }
78
- }
package/index.js DELETED
@@ -1,5 +0,0 @@
1
- const fetch = require('node-fetch').default;
2
- const core = require('./flagsmith-core');
3
- const flagsmith = core({fetch: fetch});
4
-
5
- module.exports = flagsmith;