flagsmith-nodejs 5.1.1 → 6.0.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.
@@ -44,7 +44,7 @@ export declare class AnalyticsProcessor {
44
44
  /**
45
45
  * Track a single evaluation event for a feature.
46
46
  *
47
- * This method is called whenever {@link Flags.isFeatureEnabled}, {@link Flags.getFeatureValue} or {@link Flags.getFlag} are called.
47
+ * @see FlagsmithConfig.enableAnalytics
48
48
  */
49
49
  trackFeature(featureName: string): void;
50
50
  }
@@ -67,7 +67,7 @@ class AnalyticsProcessor {
67
67
  /**
68
68
  * Track a single evaluation event for a feature.
69
69
  *
70
- * This method is called whenever {@link Flags.isFeatureEnabled}, {@link Flags.getFeatureValue} or {@link Flags.getFlag} are called.
70
+ * @see FlagsmithConfig.enableAnalytics
71
71
  */
72
72
  trackFeature(featureName) {
73
73
  this.analyticsData[featureName] = (this.analyticsData[featureName] || 0) + 1;
@@ -11,6 +11,30 @@ export { FlagsmithAPIError, FlagsmithClientError } from './errors.js';
11
11
  export { DefaultFlag, Flags } from './models.js';
12
12
  export { EnvironmentDataPollingManager } from './polling_manager.js';
13
13
  export { FlagsmithCache, FlagsmithConfig } from './types.js';
14
+ /**
15
+ * A client for evaluating Flagsmith feature flags.
16
+ *
17
+ * Flags are evaluated remotely by the Flagsmith API over HTTP by default.
18
+ * To evaluate flags locally, create the client using {@link FlagsmithConfig.enableLocalEvaluation} and a server-side SDK key.
19
+ *
20
+ * @example
21
+ * import { Flagsmith, Flags, DefaultFlag } from 'flagsmith-nodejs'
22
+ *
23
+ * const flagsmith = new Flagsmith({
24
+ * environmentKey: 'your_sdk_key',
25
+ * defaultFlagHandler: (flagKey: string) => { new DefaultFlag(...) },
26
+ * });
27
+ *
28
+ * // Fetch the current environment flags
29
+ * const environmentFlags: Flags = flagsmith.getEnvironmentFlags()
30
+ * const isFooEnabled: boolean = environmentFlags.isFeatureEnabled('foo')
31
+ *
32
+ * // Evaluate flags for any identity
33
+ * const identityFlags: Flags = flagsmith.getIdentityFlags('my_user_123', {'vip': true})
34
+ * const bannerVariation: string = identityFlags.getFeatureValue('banner_flag')
35
+ *
36
+ * @see FlagsmithConfig
37
+ */
14
38
  export declare class Flagsmith {
15
39
  environmentKey?: string;
16
40
  apiUrl?: string;
@@ -29,53 +53,24 @@ export declare class Flagsmith {
29
53
  identitiesUrl?: string;
30
54
  environmentUrl?: string;
31
55
  environmentDataPollingManager?: EnvironmentDataPollingManager;
32
- environment: EnvironmentModel;
56
+ private environment?;
33
57
  offlineMode: boolean;
34
58
  offlineHandler?: BaseOfflineHandler;
35
59
  identitiesWithOverridesByIdentifier?: Map<string, IdentityModel>;
36
60
  private cache?;
37
- private onEnvironmentChange?;
61
+ private onEnvironmentChange;
38
62
  private analyticsProcessor?;
39
63
  private logger;
40
64
  private customFetch;
65
+ private readonly requestRetryDelayMilliseconds;
41
66
  /**
42
- * A Flagsmith client.
67
+ * Creates a new {@link Flagsmith} client.
43
68
  *
44
- * Provides an interface for interacting with the Flagsmith http API.
45
- * Basic Usage::
46
- *
47
- * import flagsmith from Flagsmith
48
- * const flagsmith = new Flagsmith({environmentKey: '<your API key>'});
49
- * const environmentFlags = flagsmith.getEnvironmentFlags();
50
- * const featureEnabled = environmentFlags.isFeatureEnabled('foo');
51
- * const identityFlags = flagsmith.getIdentityFlags('identifier', {'foo': 'bar'});
52
- * const featureEnabledForIdentity = identityFlags.isFeatureEnabled("foo")
53
- *
54
- * @param {string} data.environmentKey: The environment key obtained from Flagsmith interface
55
- * Required unless offlineMode is True.
56
- @param {string} data.apiUrl: Override the URL of the Flagsmith API to communicate with
57
- @param data.customHeaders: Additional headers to add to requests made to the
58
- Flagsmith API
59
- @param {number} data.requestTimeoutSeconds: Number of seconds to wait for a request to
60
- complete before terminating the request
61
- @param {boolean} data.enableLocalEvaluation: Enables local evaluation of flags
62
- @param {number} data.environmentRefreshIntervalSeconds: If using local evaluation,
63
- specify the interval period between refreshes of local environment data
64
- @param {number} data.retries: a urllib3.Retry object to use on all http requests to the
65
- Flagsmith API
66
- @param {boolean} data.enableAnalytics: if enabled, sends additional requests to the Flagsmith
67
- API to power flag analytics charts
68
- @param data.defaultFlagHandler: callable which will be used in the case where
69
- flags cannot be retrieved from the API or a non-existent feature is
70
- requested
71
- @param data.logger: an instance of the pino Logger class to use for logging
72
- @param {boolean} data.offlineMode: sets the client into offline mode. Relies on offlineHandler for
73
- evaluating flags.
74
- @param {BaseOfflineHandler} data.offlineHandler: provide a handler for offline logic. Used to get environment
75
- document from another source when in offlineMode. Works in place of
76
- defaultFlagHandler if offlineMode is not set and using remote evaluation.
77
- */
78
- constructor(data?: FlagsmithConfig);
69
+ * If using local evaluation, the environment will be fetched lazily when needed by any method. Polling the
70
+ * environment for updates will start after {@link environmentRefreshIntervalSeconds} once the client is created.
71
+ * @param data The {@link FlagsmithConfig} options for this client.
72
+ */
73
+ constructor(data: FlagsmithConfig);
79
74
  /**
80
75
  * Get all the default for flags for the current environment.
81
76
  *
@@ -110,10 +105,11 @@ export declare class Flagsmith {
110
105
  getIdentitySegments(identifier: string, traits?: {
111
106
  [key: string]: any;
112
107
  }): Promise<SegmentModel[]>;
108
+ private fetchEnvironment;
113
109
  /**
114
- * Updates the environment state for local flag evaluation.
115
- * Sets a local promise to prevent race conditions in getIdentityFlags / getIdentitySegments.
116
- * You only need to call this if you wish to bypass environmentRefreshIntervalSeconds.
110
+ * Fetch the latest environment state from the Flagsmith API to use for local flag evaluation.
111
+ *
112
+ * If the environment is currently being fetched, calling this method will not cause additional fetches.
117
113
  */
118
114
  updateEnvironment(): Promise<void>;
119
115
  close(): Promise<void>;
@@ -121,7 +117,13 @@ export declare class Flagsmith {
121
117
  /**
122
118
  * This promise ensures that the environment is retrieved before attempting to locally evaluate.
123
119
  */
124
- private environmentPromise;
120
+ private environmentPromise?;
121
+ /**
122
+ * Returns the current environment, fetching it from the API if needed.
123
+ *
124
+ * Calling this method concurrently while the environment is being fetched will not cause additional requests.
125
+ */
126
+ getEnvironment(): Promise<EnvironmentModel>;
125
127
  private getEnvironmentFromApi;
126
128
  private getEnvironmentFlagsFromDocument;
127
129
  private getIdentityFlagsFromDocument;
@@ -24,6 +24,30 @@ var polling_manager_js_2 = require("./polling_manager.js");
24
24
  Object.defineProperty(exports, "EnvironmentDataPollingManager", { enumerable: true, get: function () { return polling_manager_js_2.EnvironmentDataPollingManager; } });
25
25
  const DEFAULT_API_URL = 'https://edge.api.flagsmith.com/api/v1/';
26
26
  const DEFAULT_REQUEST_TIMEOUT_SECONDS = 10;
27
+ /**
28
+ * A client for evaluating Flagsmith feature flags.
29
+ *
30
+ * Flags are evaluated remotely by the Flagsmith API over HTTP by default.
31
+ * To evaluate flags locally, create the client using {@link FlagsmithConfig.enableLocalEvaluation} and a server-side SDK key.
32
+ *
33
+ * @example
34
+ * import { Flagsmith, Flags, DefaultFlag } from 'flagsmith-nodejs'
35
+ *
36
+ * const flagsmith = new Flagsmith({
37
+ * environmentKey: 'your_sdk_key',
38
+ * defaultFlagHandler: (flagKey: string) => { new DefaultFlag(...) },
39
+ * });
40
+ *
41
+ * // Fetch the current environment flags
42
+ * const environmentFlags: Flags = flagsmith.getEnvironmentFlags()
43
+ * const isFooEnabled: boolean = environmentFlags.isFeatureEnabled('foo')
44
+ *
45
+ * // Evaluate flags for any identity
46
+ * const identityFlags: Flags = flagsmith.getIdentityFlags('my_user_123', {'vip': true})
47
+ * const bannerVariation: string = identityFlags.getFeatureValue('banner_flag')
48
+ *
49
+ * @see FlagsmithConfig
50
+ */
27
51
  class Flagsmith {
28
52
  environmentKey = undefined;
29
53
  apiUrl = undefined;
@@ -49,61 +73,30 @@ class Flagsmith {
49
73
  analyticsProcessor;
50
74
  logger;
51
75
  customFetch;
76
+ requestRetryDelayMilliseconds;
52
77
  /**
53
- * A Flagsmith client.
78
+ * Creates a new {@link Flagsmith} client.
54
79
  *
55
- * Provides an interface for interacting with the Flagsmith http API.
56
- * Basic Usage::
57
- *
58
- * import flagsmith from Flagsmith
59
- * const flagsmith = new Flagsmith({environmentKey: '<your API key>'});
60
- * const environmentFlags = flagsmith.getEnvironmentFlags();
61
- * const featureEnabled = environmentFlags.isFeatureEnabled('foo');
62
- * const identityFlags = flagsmith.getIdentityFlags('identifier', {'foo': 'bar'});
63
- * const featureEnabledForIdentity = identityFlags.isFeatureEnabled("foo")
64
- *
65
- * @param {string} data.environmentKey: The environment key obtained from Flagsmith interface
66
- * Required unless offlineMode is True.
67
- @param {string} data.apiUrl: Override the URL of the Flagsmith API to communicate with
68
- @param data.customHeaders: Additional headers to add to requests made to the
69
- Flagsmith API
70
- @param {number} data.requestTimeoutSeconds: Number of seconds to wait for a request to
71
- complete before terminating the request
72
- @param {boolean} data.enableLocalEvaluation: Enables local evaluation of flags
73
- @param {number} data.environmentRefreshIntervalSeconds: If using local evaluation,
74
- specify the interval period between refreshes of local environment data
75
- @param {number} data.retries: a urllib3.Retry object to use on all http requests to the
76
- Flagsmith API
77
- @param {boolean} data.enableAnalytics: if enabled, sends additional requests to the Flagsmith
78
- API to power flag analytics charts
79
- @param data.defaultFlagHandler: callable which will be used in the case where
80
- flags cannot be retrieved from the API or a non-existent feature is
81
- requested
82
- @param data.logger: an instance of the pino Logger class to use for logging
83
- @param {boolean} data.offlineMode: sets the client into offline mode. Relies on offlineHandler for
84
- evaluating flags.
85
- @param {BaseOfflineHandler} data.offlineHandler: provide a handler for offline logic. Used to get environment
86
- document from another source when in offlineMode. Works in place of
87
- defaultFlagHandler if offlineMode is not set and using remote evaluation.
88
- */
89
- constructor(data = {}) {
90
- // if (!data.offlineMode && !data.environmentKey) {
91
- // throw new Error('ValueError: environmentKey is required.');
92
- // }
80
+ * If using local evaluation, the environment will be fetched lazily when needed by any method. Polling the
81
+ * environment for updates will start after {@link environmentRefreshIntervalSeconds} once the client is created.
82
+ * @param data The {@link FlagsmithConfig} options for this client.
83
+ */
84
+ constructor(data) {
93
85
  this.agent = data.agent;
94
86
  this.customFetch = data.fetch ?? fetch;
95
87
  this.environmentKey = data.environmentKey;
96
- this.apiUrl = data.apiUrl || this.apiUrl;
88
+ this.apiUrl = data.apiUrl || DEFAULT_API_URL;
97
89
  this.customHeaders = data.customHeaders;
98
90
  this.requestTimeoutMs =
99
91
  1000 * (data.requestTimeoutSeconds ?? DEFAULT_REQUEST_TIMEOUT_SECONDS);
92
+ this.requestRetryDelayMilliseconds = data.requestRetryDelayMilliseconds ?? 1000;
100
93
  this.enableLocalEvaluation = data.enableLocalEvaluation;
101
94
  this.environmentRefreshIntervalSeconds =
102
95
  data.environmentRefreshIntervalSeconds || this.environmentRefreshIntervalSeconds;
103
96
  this.retries = data.retries;
104
97
  this.enableAnalytics = data.enableAnalytics || false;
105
98
  this.defaultFlagHandler = data.defaultFlagHandler;
106
- this.onEnvironmentChange = data.onEnvironmentChange;
99
+ this.onEnvironmentChange = (error, result) => data.onEnvironmentChange?.(error, result);
107
100
  this.logger = data.logger || (0, pino_1.pino)();
108
101
  this.offlineMode = data.offlineMode || false;
109
102
  this.offlineHandler = data.offlineHandler;
@@ -114,9 +107,6 @@ class Flagsmith {
114
107
  else if (this.defaultFlagHandler && this.offlineHandler) {
115
108
  throw new Error('ValueError: Cannot use both defaultFlagHandler and offlineHandler.');
116
109
  }
117
- if (this.offlineHandler) {
118
- this.environment = this.offlineHandler.getEnvironment();
119
- }
120
110
  if (!!data.cache) {
121
111
  this.cache = data.cache;
122
112
  }
@@ -132,11 +122,12 @@ class Flagsmith {
132
122
  this.environmentUrl = `${this.apiUrl}environment-document/`;
133
123
  if (this.enableLocalEvaluation) {
134
124
  if (!this.environmentKey.startsWith('ser.')) {
135
- console.error('In order to use local evaluation, please generate a server key in the environment settings page.');
125
+ throw new Error('Using local evaluation requires a server-side environment key');
126
+ }
127
+ if (this.environmentRefreshIntervalSeconds > 0) {
128
+ this.environmentDataPollingManager = new polling_manager_js_1.EnvironmentDataPollingManager(this, this.environmentRefreshIntervalSeconds, this.logger);
129
+ this.environmentDataPollingManager.start();
136
130
  }
137
- this.environmentDataPollingManager = new polling_manager_js_1.EnvironmentDataPollingManager(this, this.environmentRefreshIntervalSeconds);
138
- this.environmentDataPollingManager.start();
139
- this.updateEnvironment();
140
131
  }
141
132
  if (data.enableAnalytics) {
142
133
  this.analyticsProcessor = new analytics_js_1.AnalyticsProcessor({
@@ -158,15 +149,22 @@ class Flagsmith {
158
149
  if (!!cachedItem) {
159
150
  return cachedItem;
160
151
  }
161
- if (this.enableLocalEvaluation && !this.offlineMode) {
162
- return new Promise((resolve, reject) => this.environmentPromise.then(() => {
163
- resolve(this.getEnvironmentFlagsFromDocument());
164
- }).catch(e => reject(e)));
152
+ try {
153
+ if (this.enableLocalEvaluation || this.offlineMode) {
154
+ return await this.getEnvironmentFlagsFromDocument();
155
+ }
156
+ return await this.getEnvironmentFlagsFromApi();
165
157
  }
166
- if (this.environment) {
167
- return this.getEnvironmentFlagsFromDocument();
158
+ catch (error) {
159
+ if (!this.defaultFlagHandler) {
160
+ throw new Error('getEnvironmentFlags failed and no default flag handler was provided', { cause: error });
161
+ }
162
+ this.logger.error(error, 'getEnvironmentFlags failed');
163
+ return new models_js_1.Flags({
164
+ flags: {},
165
+ defaultFlagHandler: this.defaultFlagHandler
166
+ });
168
167
  }
169
- return this.getEnvironmentFlagsFromApi();
170
168
  }
171
169
  /**
172
170
  * Get all the flags for the current environment for a given identity. Will also
@@ -188,15 +186,22 @@ class Flagsmith {
188
186
  return cachedItem;
189
187
  }
190
188
  traits = traits || {};
191
- if (this.enableLocalEvaluation) {
192
- return new Promise((resolve, reject) => this.environmentPromise.then(() => {
193
- resolve(this.getIdentityFlagsFromDocument(identifier, traits || {}));
194
- }).catch(e => reject(e)));
189
+ try {
190
+ if (this.enableLocalEvaluation || this.offlineMode) {
191
+ return await this.getIdentityFlagsFromDocument(identifier, traits || {});
192
+ }
193
+ return await this.getIdentityFlagsFromApi(identifier, traits, transient);
195
194
  }
196
- if (this.offlineMode) {
197
- return this.getIdentityFlagsFromDocument(identifier, traits || {});
195
+ catch (error) {
196
+ if (!this.defaultFlagHandler) {
197
+ throw new Error('getIdentityFlags failed and no default flag handler was provided', { cause: error });
198
+ }
199
+ this.logger.error(error, 'getIdentityFlags failed');
200
+ return new models_js_1.Flags({
201
+ flags: {},
202
+ defaultFlagHandler: this.defaultFlagHandler
203
+ });
198
204
  }
199
- return this.getIdentityFlagsFromApi(identifier, traits, transient);
200
205
  }
201
206
  /**
202
207
  * Get the segments for the current environment for a given identity. Will also
@@ -209,57 +214,59 @@ class Flagsmith {
209
214
  Flagsmith, e.g. {"num_orders": 10}
210
215
  * @returns Segments that the given identity belongs to.
211
216
  */
212
- getIdentitySegments(identifier, traits) {
217
+ async getIdentitySegments(identifier, traits) {
213
218
  if (!identifier) {
214
219
  throw new Error('`identifier` argument is missing or invalid.');
215
220
  }
221
+ if (!this.enableLocalEvaluation) {
222
+ this.logger.error('This function is only permitted with local evaluation.');
223
+ return Promise.resolve([]);
224
+ }
216
225
  traits = traits || {};
217
- if (this.enableLocalEvaluation) {
218
- return new Promise((resolve, reject) => {
219
- return this.environmentPromise.then(() => {
220
- const identityModel = this.getIdentityModel(identifier, Object.keys(traits || {}).map(key => ({
221
- key,
222
- value: traits?.[key]
223
- })));
224
- const segments = (0, evaluators_js_1.getIdentitySegments)(this.environment, identityModel);
225
- return resolve(segments);
226
- }).catch(e => reject(e));
227
- });
226
+ const environment = await this.getEnvironment();
227
+ const identityModel = this.getIdentityModel(environment, identifier, Object.keys(traits || {}).map(key => ({
228
+ key,
229
+ value: traits?.[key]
230
+ })));
231
+ return (0, evaluators_js_1.getIdentitySegments)(environment, identityModel);
232
+ }
233
+ async fetchEnvironment() {
234
+ const deferred = new utils_js_1.Deferred();
235
+ this.environmentPromise = deferred.promise;
236
+ try {
237
+ const environment = await this.getEnvironmentFromApi();
238
+ this.environment = environment;
239
+ if (environment.identityOverrides?.length) {
240
+ this.identitiesWithOverridesByIdentifier = new Map(environment.identityOverrides.map(identity => [identity.identifier, identity]));
241
+ }
242
+ deferred.resolve(environment);
243
+ return deferred.promise;
244
+ }
245
+ catch (error) {
246
+ deferred.reject(error);
247
+ return deferred.promise;
248
+ }
249
+ finally {
250
+ this.environmentPromise = undefined;
228
251
  }
229
- console.error('This function is only permitted with local evaluation.');
230
- return Promise.resolve([]);
231
252
  }
232
253
  /**
233
- * Updates the environment state for local flag evaluation.
234
- * Sets a local promise to prevent race conditions in getIdentityFlags / getIdentitySegments.
235
- * You only need to call this if you wish to bypass environmentRefreshIntervalSeconds.
254
+ * Fetch the latest environment state from the Flagsmith API to use for local flag evaluation.
255
+ *
256
+ * If the environment is currently being fetched, calling this method will not cause additional fetches.
236
257
  */
237
258
  async updateEnvironment() {
238
259
  try {
239
- const request = this.getEnvironmentFromApi();
240
- if (!this.environmentPromise) {
241
- this.environmentPromise = request.then(res => {
242
- this.environment = res;
243
- });
260
+ if (this.environmentPromise) {
244
261
  await this.environmentPromise;
262
+ return;
245
263
  }
246
- else {
247
- this.environment = await request;
248
- }
249
- if (this.environment.identityOverrides?.length) {
250
- this.identitiesWithOverridesByIdentifier = new Map(this.environment.identityOverrides.map(identity => [
251
- identity.identifier,
252
- identity
253
- ]));
254
- }
255
- if (this.onEnvironmentChange) {
256
- this.onEnvironmentChange(null, this.environment);
257
- }
264
+ const environment = await this.fetchEnvironment();
265
+ this.onEnvironmentChange(null, environment);
258
266
  }
259
267
  catch (e) {
260
- if (this.onEnvironmentChange) {
261
- this.onEnvironmentChange(e, this.environment);
262
- }
268
+ this.logger.error(e, 'updateEnvironment failed');
269
+ this.onEnvironmentChange(e);
263
270
  }
264
271
  }
265
272
  async close() {
@@ -280,7 +287,7 @@ class Flagsmith {
280
287
  method: method,
281
288
  body: JSON.stringify(body),
282
289
  headers: headers
283
- }, this.retries, this.requestTimeoutMs, this.customFetch);
290
+ }, this.retries, this.requestTimeoutMs, this.requestRetryDelayMilliseconds, this.customFetch);
284
291
  if (data.status !== 200) {
285
292
  throw new errors_js_1.FlagsmithAPIError(`Invalid request made to Flagsmith API. Response status code: ${data.status}`);
286
293
  }
@@ -290,6 +297,23 @@ class Flagsmith {
290
297
  * This promise ensures that the environment is retrieved before attempting to locally evaluate.
291
298
  */
292
299
  environmentPromise;
300
+ /**
301
+ * Returns the current environment, fetching it from the API if needed.
302
+ *
303
+ * Calling this method concurrently while the environment is being fetched will not cause additional requests.
304
+ */
305
+ async getEnvironment() {
306
+ if (this.offlineHandler) {
307
+ return this.offlineHandler.getEnvironment();
308
+ }
309
+ if (this.environment) {
310
+ return this.environment;
311
+ }
312
+ if (!this.environmentPromise) {
313
+ this.environmentPromise = this.fetchEnvironment();
314
+ }
315
+ return this.environmentPromise;
316
+ }
293
317
  async getEnvironmentFromApi() {
294
318
  if (!this.environmentUrl) {
295
319
  throw new Error('`apiUrl` argument is missing or invalid.');
@@ -298,8 +322,9 @@ class Flagsmith {
298
322
  return (0, util_js_1.buildEnvironmentModel)(environment_data);
299
323
  }
300
324
  async getEnvironmentFlagsFromDocument() {
325
+ const environment = await this.getEnvironment();
301
326
  const flags = models_js_1.Flags.fromFeatureStateModels({
302
- featureStates: (0, index_js_1.getEnvironmentFeatureStates)(this.environment),
327
+ featureStates: (0, index_js_1.getEnvironmentFeatureStates)(environment),
303
328
  analyticsProcessor: this.analyticsProcessor,
304
329
  defaultFlagHandler: this.defaultFlagHandler
305
330
  });
@@ -309,11 +334,12 @@ class Flagsmith {
309
334
  return flags;
310
335
  }
311
336
  async getIdentityFlagsFromDocument(identifier, traits) {
312
- const identityModel = this.getIdentityModel(identifier, Object.keys(traits).map(key => ({
337
+ const environment = await this.getEnvironment();
338
+ const identityModel = this.getIdentityModel(environment, identifier, Object.keys(traits).map(key => ({
313
339
  key,
314
340
  value: traits[key]
315
341
  })));
316
- const featureStates = (0, index_js_1.getIdentityFeatureStates)(this.environment, identityModel);
342
+ const featureStates = (0, index_js_1.getIdentityFeatureStates)(environment, identityModel);
317
343
  const flags = models_js_1.Flags.fromFeatureStateModels({
318
344
  featureStates: featureStates,
319
345
  analyticsProcessor: this.analyticsProcessor,
@@ -329,69 +355,41 @@ class Flagsmith {
329
355
  if (!this.environmentFlagsUrl) {
330
356
  throw new Error('`apiUrl` argument is missing or invalid.');
331
357
  }
332
- try {
333
- const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
334
- const flags = models_js_1.Flags.fromAPIFlags({
335
- apiFlags: apiFlags,
336
- analyticsProcessor: this.analyticsProcessor,
337
- defaultFlagHandler: this.defaultFlagHandler
338
- });
339
- if (!!this.cache) {
340
- await this.cache.set('flags', flags);
341
- }
342
- return flags;
343
- }
344
- catch (e) {
345
- if (this.offlineHandler) {
346
- return this.getEnvironmentFlagsFromDocument();
347
- }
348
- if (this.defaultFlagHandler) {
349
- return new models_js_1.Flags({
350
- flags: {},
351
- defaultFlagHandler: this.defaultFlagHandler
352
- });
353
- }
354
- throw e;
358
+ const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
359
+ const flags = models_js_1.Flags.fromAPIFlags({
360
+ apiFlags: apiFlags,
361
+ analyticsProcessor: this.analyticsProcessor,
362
+ defaultFlagHandler: this.defaultFlagHandler
363
+ });
364
+ if (!!this.cache) {
365
+ await this.cache.set('flags', flags);
355
366
  }
367
+ return flags;
356
368
  }
357
369
  async getIdentityFlagsFromApi(identifier, traits, transient = false) {
358
370
  if (!this.identitiesUrl) {
359
371
  throw new Error('`apiUrl` argument is missing or invalid.');
360
372
  }
361
- try {
362
- const data = (0, utils_js_1.generateIdentitiesData)(identifier, traits, transient);
363
- const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
364
- const flags = models_js_1.Flags.fromAPIFlags({
365
- apiFlags: jsonResponse['flags'],
366
- analyticsProcessor: this.analyticsProcessor,
367
- defaultFlagHandler: this.defaultFlagHandler
368
- });
369
- if (!!this.cache) {
370
- await this.cache.set(`flags-${identifier}`, flags);
371
- }
372
- return flags;
373
- }
374
- catch (e) {
375
- if (this.offlineHandler) {
376
- return this.getIdentityFlagsFromDocument(identifier, traits);
377
- }
378
- if (this.defaultFlagHandler) {
379
- return new models_js_1.Flags({
380
- flags: {},
381
- defaultFlagHandler: this.defaultFlagHandler
382
- });
383
- }
384
- throw e;
373
+ const data = (0, utils_js_1.generateIdentitiesData)(identifier, traits, transient);
374
+ const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
375
+ const flags = models_js_1.Flags.fromAPIFlags({
376
+ apiFlags: jsonResponse['flags'],
377
+ analyticsProcessor: this.analyticsProcessor,
378
+ defaultFlagHandler: this.defaultFlagHandler
379
+ });
380
+ if (!!this.cache) {
381
+ await this.cache.set(`flags-${identifier}`, flags);
385
382
  }
383
+ return flags;
386
384
  }
387
- getIdentityModel(identifier, traits) {
385
+ getIdentityModel(environment, identifier, traits) {
388
386
  const traitModels = traits.map(trait => new index_js_3.TraitModel(trait.key, trait.value));
389
387
  let identityWithOverrides = this.identitiesWithOverridesByIdentifier?.get(identifier);
390
388
  if (identityWithOverrides) {
391
389
  identityWithOverrides.updateTraits(traitModels);
392
390
  return identityWithOverrides;
393
391
  }
394
- return new index_js_2.IdentityModel('0', traitModels, [], this.environment.apiKey, identifier);
392
+ return new index_js_2.IdentityModel('0', traitModels, [], environment.apiKey, identifier);
395
393
  }
396
394
  }
397
395
  exports.Flagsmith = Flagsmith;
@@ -1,19 +1,20 @@
1
1
  import { FeatureStateModel } from '../flagsmith-engine/features/models.js';
2
2
  import { AnalyticsProcessor } from './analytics.js';
3
+ type FlagValue = string | number | boolean | undefined;
3
4
  export declare class BaseFlag {
4
5
  enabled: boolean;
5
- value: string | number | boolean | undefined;
6
+ value: FlagValue;
6
7
  isDefault: boolean;
7
- constructor(value: string | number | boolean | undefined, enabled: boolean, isDefault: boolean);
8
+ constructor(value: FlagValue, enabled: boolean, isDefault: boolean);
8
9
  }
9
10
  export declare class DefaultFlag extends BaseFlag {
10
- constructor(value: string | number | boolean | undefined, enabled: boolean);
11
+ constructor(value: FlagValue, enabled: boolean);
11
12
  }
12
13
  export declare class Flag extends BaseFlag {
13
14
  featureId: number;
14
15
  featureName: string;
15
16
  constructor(params: {
16
- value: string | number | boolean | undefined;
17
+ value: FlagValue;
17
18
  enabled: boolean;
18
19
  isDefault?: boolean;
19
20
  featureId: number;
@@ -50,6 +51,7 @@ export declare class Flags {
50
51
  }): Flags;
51
52
  allFlags(): Flag[];
52
53
  getFlag(featureName: string): BaseFlag;
53
- getFeatureValue(featureName: string): any;
54
+ getFeatureValue(featureName: string): FlagValue;
54
55
  isFeatureEnabled(featureName: string): boolean;
55
56
  }
57
+ export {};
@@ -1,9 +1,11 @@
1
1
  import Flagsmith from './index.js';
2
+ import { Logger } from 'pino';
2
3
  export declare class EnvironmentDataPollingManager {
3
4
  private interval?;
4
5
  private main;
5
6
  private refreshIntervalSeconds;
6
- constructor(main: Flagsmith, refreshIntervalSeconds: number);
7
+ private logger;
8
+ constructor(main: Flagsmith, refreshIntervalSeconds: number, logger: Logger);
7
9
  start(): void;
8
10
  stop(): void;
9
11
  }
@@ -5,16 +5,23 @@ class EnvironmentDataPollingManager {
5
5
  interval;
6
6
  main;
7
7
  refreshIntervalSeconds;
8
- constructor(main, refreshIntervalSeconds) {
8
+ logger;
9
+ constructor(main, refreshIntervalSeconds, logger) {
9
10
  this.main = main;
10
11
  this.refreshIntervalSeconds = refreshIntervalSeconds;
12
+ this.logger = logger;
11
13
  }
12
14
  start() {
13
15
  const updateEnvironment = () => {
14
16
  if (this.interval)
15
17
  clearInterval(this.interval);
16
18
  this.interval = setInterval(async () => {
17
- await this.main.updateEnvironment();
19
+ try {
20
+ await this.main.updateEnvironment();
21
+ }
22
+ catch (error) {
23
+ this.logger.error(error, 'failed to poll environment');
24
+ }
18
25
  }, this.refreshIntervalSeconds * 1000);
19
26
  };
20
27
  updateEnvironment();