@launchdarkly/js-client-sdk-common 1.20.0 → 1.22.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/CHANGELOG.md +38 -0
- package/dist/cjs/LDClientImpl.d.ts.map +1 -1
- package/dist/cjs/api/LDOptions.d.ts +8 -0
- package/dist/cjs/api/LDOptions.d.ts.map +1 -1
- package/dist/cjs/api/datasource/DataSourceEntry.d.ts +45 -0
- package/dist/cjs/api/datasource/DataSourceEntry.d.ts.map +1 -0
- package/dist/cjs/api/datasource/FDv2ConnectionMode.d.ts +30 -0
- package/dist/cjs/api/datasource/FDv2ConnectionMode.d.ts.map +1 -0
- package/dist/cjs/api/datasource/LDClientDataSystemOptions.d.ts +75 -0
- package/dist/cjs/api/datasource/LDClientDataSystemOptions.d.ts.map +1 -0
- package/dist/cjs/api/datasource/ModeDefinition.d.ts +21 -0
- package/dist/cjs/api/datasource/ModeDefinition.d.ts.map +1 -0
- package/dist/cjs/api/datasource/ModeResolution.d.ts +75 -0
- package/dist/cjs/api/datasource/ModeResolution.d.ts.map +1 -0
- package/dist/cjs/api/datasource/index.d.ts +6 -0
- package/dist/cjs/api/datasource/index.d.ts.map +1 -0
- package/dist/cjs/api/index.d.ts +1 -0
- package/dist/cjs/api/index.d.ts.map +1 -1
- package/dist/cjs/configuration/Configuration.d.ts +6 -1
- package/dist/cjs/configuration/Configuration.d.ts.map +1 -1
- package/dist/cjs/configuration/validateOptions.d.ts +95 -0
- package/dist/cjs/configuration/validateOptions.d.ts.map +1 -0
- package/dist/cjs/configuration/validators.d.ts +5 -2
- package/dist/cjs/configuration/validators.d.ts.map +1 -1
- package/dist/cjs/datasource/ConnectionModeConfig.d.ts +19 -0
- package/dist/cjs/datasource/ConnectionModeConfig.d.ts.map +1 -0
- package/dist/cjs/datasource/LDClientDataSystemOptions.d.ts +20 -0
- package/dist/cjs/datasource/LDClientDataSystemOptions.d.ts.map +1 -0
- package/dist/cjs/datasource/ModeResolver.d.ts +30 -0
- package/dist/cjs/datasource/ModeResolver.d.ts.map +1 -0
- package/dist/cjs/datasource/StateDebounceManager.d.ts +92 -0
- package/dist/cjs/datasource/StateDebounceManager.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/AsyncQueue.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/AsyncQueue.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/CacheInitializer.d.ts +17 -0
- package/dist/cjs/datasource/fdv2/CacheInitializer.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/Conditions.d.ts +73 -0
- package/dist/cjs/datasource/fdv2/Conditions.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/FDv1PollingSynchronizer.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/FDv1PollingSynchronizer.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/FDv2DataSource.d.ts +52 -0
- package/dist/cjs/datasource/fdv2/FDv2DataSource.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/FDv2Requestor.d.ts +45 -0
- package/dist/cjs/datasource/fdv2/FDv2Requestor.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/FDv2SourceResult.d.ts +84 -0
- package/dist/cjs/datasource/fdv2/FDv2SourceResult.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/Initializer.d.ts +40 -0
- package/dist/cjs/datasource/fdv2/Initializer.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/PollingBase.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/PollingBase.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/PollingInitializer.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/PollingInitializer.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/PollingSynchronizer.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/PollingSynchronizer.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/SourceManager.d.ts +88 -0
- package/dist/cjs/datasource/fdv2/SourceManager.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/StreamingFDv2Base.d.ts +11 -0
- package/dist/cjs/datasource/fdv2/StreamingFDv2Base.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/StreamingInitializerFDv2.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/StreamingInitializerFDv2.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/StreamingSynchronizerFDv2.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/StreamingSynchronizerFDv2.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/Synchronizer.d.ts +49 -0
- package/dist/cjs/datasource/fdv2/Synchronizer.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/calculatePollDelay.d.ts +2 -0
- package/dist/cjs/datasource/fdv2/calculatePollDelay.d.ts.map +1 -0
- package/dist/cjs/datasource/fdv2/index.d.ts +20 -0
- package/dist/cjs/datasource/fdv2/index.d.ts.map +1 -0
- package/dist/cjs/datasource/flagEvalMapper.d.ts +3 -3
- package/dist/cjs/flag-manager/FlagManager.d.ts +2 -1
- package/dist/cjs/flag-manager/FlagManager.d.ts.map +1 -1
- package/dist/cjs/flag-manager/FlagPersistence.d.ts +8 -1
- package/dist/cjs/flag-manager/FlagPersistence.d.ts.map +1 -1
- package/dist/cjs/index.cjs +411 -100
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/storage/freshness.d.ts +27 -0
- package/dist/cjs/storage/freshness.d.ts.map +1 -0
- package/dist/cjs/storage/loadCachedFlags.d.ts +25 -0
- package/dist/cjs/storage/loadCachedFlags.d.ts.map +1 -0
- package/dist/esm/LDClientImpl.d.ts.map +1 -1
- package/dist/esm/api/LDOptions.d.ts +8 -0
- package/dist/esm/api/LDOptions.d.ts.map +1 -1
- package/dist/esm/api/datasource/DataSourceEntry.d.ts +45 -0
- package/dist/esm/api/datasource/DataSourceEntry.d.ts.map +1 -0
- package/dist/esm/api/datasource/FDv2ConnectionMode.d.ts +30 -0
- package/dist/esm/api/datasource/FDv2ConnectionMode.d.ts.map +1 -0
- package/dist/esm/api/datasource/LDClientDataSystemOptions.d.ts +75 -0
- package/dist/esm/api/datasource/LDClientDataSystemOptions.d.ts.map +1 -0
- package/dist/esm/api/datasource/ModeDefinition.d.ts +21 -0
- package/dist/esm/api/datasource/ModeDefinition.d.ts.map +1 -0
- package/dist/esm/api/datasource/ModeResolution.d.ts +75 -0
- package/dist/esm/api/datasource/ModeResolution.d.ts.map +1 -0
- package/dist/esm/api/datasource/index.d.ts +6 -0
- package/dist/esm/api/datasource/index.d.ts.map +1 -0
- package/dist/esm/api/index.d.ts +1 -0
- package/dist/esm/api/index.d.ts.map +1 -1
- package/dist/esm/configuration/Configuration.d.ts +6 -1
- package/dist/esm/configuration/Configuration.d.ts.map +1 -1
- package/dist/esm/configuration/validateOptions.d.ts +95 -0
- package/dist/esm/configuration/validateOptions.d.ts.map +1 -0
- package/dist/esm/configuration/validators.d.ts +5 -2
- package/dist/esm/configuration/validators.d.ts.map +1 -1
- package/dist/esm/datasource/ConnectionModeConfig.d.ts +19 -0
- package/dist/esm/datasource/ConnectionModeConfig.d.ts.map +1 -0
- package/dist/esm/datasource/LDClientDataSystemOptions.d.ts +20 -0
- package/dist/esm/datasource/LDClientDataSystemOptions.d.ts.map +1 -0
- package/dist/esm/datasource/ModeResolver.d.ts +30 -0
- package/dist/esm/datasource/ModeResolver.d.ts.map +1 -0
- package/dist/esm/datasource/StateDebounceManager.d.ts +92 -0
- package/dist/esm/datasource/StateDebounceManager.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/AsyncQueue.d.ts +2 -0
- package/dist/esm/datasource/fdv2/AsyncQueue.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/CacheInitializer.d.ts +17 -0
- package/dist/esm/datasource/fdv2/CacheInitializer.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/Conditions.d.ts +73 -0
- package/dist/esm/datasource/fdv2/Conditions.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/FDv1PollingSynchronizer.d.ts +2 -0
- package/dist/esm/datasource/fdv2/FDv1PollingSynchronizer.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/FDv2DataSource.d.ts +52 -0
- package/dist/esm/datasource/fdv2/FDv2DataSource.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/FDv2Requestor.d.ts +45 -0
- package/dist/esm/datasource/fdv2/FDv2Requestor.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/FDv2SourceResult.d.ts +84 -0
- package/dist/esm/datasource/fdv2/FDv2SourceResult.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/Initializer.d.ts +40 -0
- package/dist/esm/datasource/fdv2/Initializer.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/PollingBase.d.ts +2 -0
- package/dist/esm/datasource/fdv2/PollingBase.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/PollingInitializer.d.ts +2 -0
- package/dist/esm/datasource/fdv2/PollingInitializer.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/PollingSynchronizer.d.ts +2 -0
- package/dist/esm/datasource/fdv2/PollingSynchronizer.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/SourceManager.d.ts +88 -0
- package/dist/esm/datasource/fdv2/SourceManager.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/StreamingFDv2Base.d.ts +11 -0
- package/dist/esm/datasource/fdv2/StreamingFDv2Base.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/StreamingInitializerFDv2.d.ts +2 -0
- package/dist/esm/datasource/fdv2/StreamingInitializerFDv2.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/StreamingSynchronizerFDv2.d.ts +2 -0
- package/dist/esm/datasource/fdv2/StreamingSynchronizerFDv2.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/Synchronizer.d.ts +49 -0
- package/dist/esm/datasource/fdv2/Synchronizer.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/calculatePollDelay.d.ts +2 -0
- package/dist/esm/datasource/fdv2/calculatePollDelay.d.ts.map +1 -0
- package/dist/esm/datasource/fdv2/index.d.ts +20 -0
- package/dist/esm/datasource/fdv2/index.d.ts.map +1 -0
- package/dist/esm/datasource/flagEvalMapper.d.ts +3 -3
- package/dist/esm/flag-manager/FlagManager.d.ts +2 -1
- package/dist/esm/flag-manager/FlagManager.d.ts.map +1 -1
- package/dist/esm/flag-manager/FlagPersistence.d.ts +8 -1
- package/dist/esm/flag-manager/FlagPersistence.d.ts.map +1 -1
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +404 -102
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/storage/freshness.d.ts +27 -0
- package/dist/esm/storage/freshness.d.ts.map +1 -0
- package/dist/esm/storage/loadCachedFlags.d.ts +25 -0
- package/dist/esm/storage/loadCachedFlags.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -222,34 +222,208 @@ function createAsyncTaskQueue(logger) {
|
|
|
222
222
|
};
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
225
|
+
function isCompoundValidator(v) {
|
|
226
|
+
return 'validate' in v;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Validates an options object against a map of validators and defaults.
|
|
230
|
+
*
|
|
231
|
+
* If `input` is null, undefined, or not an object the defaults are returned
|
|
232
|
+
* (with a warning for non-nullish non-objects).
|
|
233
|
+
*
|
|
234
|
+
* Supports special validator types created by:
|
|
235
|
+
* - {@link validatorOf}: recursively validates nested objects
|
|
236
|
+
* - {@link arrayOf}: validates arrays with per-item validation
|
|
237
|
+
* - {@link anyOf}: accepts the first matching validator from a list
|
|
238
|
+
* - {@link recordOf}: validates objects with dynamic keys
|
|
239
|
+
*/
|
|
240
|
+
function validateOptions(input, validatorMap, defaults, logger, prefix) {
|
|
241
|
+
const result = { ...defaults };
|
|
242
|
+
if (jsSdkCommon.isNullish(input)) {
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
if (!jsSdkCommon.TypeValidators.Object.is(input)) {
|
|
246
|
+
logger?.warn(jsSdkCommon.OptionMessages.wrongOptionType(prefix ?? 'config', 'object', typeof input));
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
Object.entries(input).forEach(([key, value]) => {
|
|
250
|
+
const validator = validatorMap[key];
|
|
251
|
+
const name = prefix ? `${prefix}.${key}` : key;
|
|
252
|
+
if (!validator) {
|
|
253
|
+
logger?.warn(jsSdkCommon.OptionMessages.unknownOption(name));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (jsSdkCommon.isNullish(value)) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (isCompoundValidator(validator)) {
|
|
260
|
+
const validated = validator.validate(value, name, logger, defaults[key]);
|
|
261
|
+
if (validated !== undefined) {
|
|
262
|
+
result[key] = validated.value;
|
|
263
|
+
}
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (validator.is(value)) {
|
|
267
|
+
result[key] = value;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Validation failed — apply correction or fall back to default.
|
|
271
|
+
const validatorType = validator.getType();
|
|
272
|
+
if (validatorType === 'boolean') {
|
|
273
|
+
logger?.warn(jsSdkCommon.OptionMessages.wrongOptionTypeBoolean(name, typeof value));
|
|
274
|
+
result[key] = !!value;
|
|
275
|
+
}
|
|
276
|
+
else if (validatorType === 'boolean | undefined | null') {
|
|
277
|
+
logger?.warn(jsSdkCommon.OptionMessages.wrongOptionTypeBoolean(name, typeof value));
|
|
278
|
+
if (typeof value !== 'boolean' && typeof value !== 'undefined' && value !== null) {
|
|
279
|
+
result[key] = !!value;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else if (validator instanceof jsSdkCommon.NumberWithMinimum && jsSdkCommon.TypeValidators.Number.is(value)) {
|
|
283
|
+
logger?.warn(jsSdkCommon.OptionMessages.optionBelowMinimum(name, value, validator.min));
|
|
284
|
+
result[key] = validator.min;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
logger?.warn(jsSdkCommon.OptionMessages.wrongOptionType(name, validatorType, typeof value));
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Creates a validator for nested objects. When used in a validator map,
|
|
294
|
+
* `validateOptions` will recursively validate the nested object's properties.
|
|
295
|
+
* Defaults for nested fields are passed through from the parent.
|
|
296
|
+
*/
|
|
297
|
+
function validatorOf(validators, builtInDefaults) {
|
|
298
|
+
return {
|
|
299
|
+
is: (u) => jsSdkCommon.TypeValidators.Object.is(u),
|
|
300
|
+
getType: () => 'object',
|
|
301
|
+
validate(value, name, logger, defaults) {
|
|
302
|
+
if (!jsSdkCommon.TypeValidators.Object.is(value)) {
|
|
303
|
+
logger?.warn(jsSdkCommon.OptionMessages.wrongOptionType(name, 'object', typeof value));
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
const nestedDefaults = builtInDefaults ??
|
|
307
|
+
(jsSdkCommon.TypeValidators.Object.is(defaults) ? defaults : {});
|
|
308
|
+
const nested = validateOptions(value, validators, nestedDefaults, logger, name);
|
|
309
|
+
return Object.keys(nested).length > 0 ? { value: nested } : undefined;
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Creates a validator that tries each provided validator in order and uses the
|
|
315
|
+
* first one whose `is()` check passes. For compound validators the value is
|
|
316
|
+
* processed through `validate()`; for simple validators the value is accepted
|
|
317
|
+
* as-is. If no validator matches, a warning is logged and the default is
|
|
318
|
+
* preserved.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```ts
|
|
322
|
+
* // Accepts either a boolean or a nested object with specific fields:
|
|
323
|
+
* anyOf(TypeValidators.Boolean, validatorOf({ lifecycle: TypeValidators.Boolean }))
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
function anyOf(...validators) {
|
|
327
|
+
return {
|
|
328
|
+
is: (u) => validators.some((v) => v.is(u)),
|
|
329
|
+
getType: () => validators.map((v) => v.getType()).join(' | '),
|
|
330
|
+
validate(value, name, logger, defaults) {
|
|
331
|
+
const match = validators.find((v) => v.is(value));
|
|
332
|
+
if (match) {
|
|
333
|
+
return isCompoundValidator(match)
|
|
334
|
+
? match.validate(value, name, logger, defaults)
|
|
335
|
+
: { value };
|
|
336
|
+
}
|
|
337
|
+
logger?.warn(jsSdkCommon.OptionMessages.wrongOptionType(name, this.getType(), typeof value));
|
|
338
|
+
return undefined;
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const dataSourceTypeValidator = jsSdkCommon.TypeValidators.oneOf('cache', 'polling', 'streaming');
|
|
344
|
+
const connectionModeValidator = jsSdkCommon.TypeValidators.oneOf('streaming', 'polling', 'offline', 'one-shot', 'background');
|
|
345
|
+
const endpointValidators = {
|
|
346
|
+
pollingBaseUri: jsSdkCommon.TypeValidators.String,
|
|
347
|
+
streamingBaseUri: jsSdkCommon.TypeValidators.String,
|
|
348
|
+
};
|
|
349
|
+
({
|
|
350
|
+
type: dataSourceTypeValidator,
|
|
241
351
|
pollInterval: jsSdkCommon.TypeValidators.numberWithMin(30),
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
352
|
+
endpoints: validatorOf(endpointValidators),
|
|
353
|
+
});
|
|
354
|
+
({
|
|
355
|
+
type: dataSourceTypeValidator,
|
|
356
|
+
initialReconnectDelay: jsSdkCommon.TypeValidators.numberWithMin(1),
|
|
357
|
+
endpoints: validatorOf(endpointValidators),
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const modeSwitchingValidators = {
|
|
361
|
+
lifecycle: jsSdkCommon.TypeValidators.Boolean,
|
|
362
|
+
network: jsSdkCommon.TypeValidators.Boolean,
|
|
363
|
+
};
|
|
364
|
+
const dataSystemValidators = {
|
|
365
|
+
initialConnectionMode: connectionModeValidator,
|
|
366
|
+
backgroundConnectionMode: connectionModeValidator,
|
|
367
|
+
automaticModeSwitching: anyOf(jsSdkCommon.TypeValidators.Boolean, validatorOf(modeSwitchingValidators)),
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Default FDv2 data system configuration for browser SDKs.
|
|
371
|
+
*/
|
|
372
|
+
const BROWSER_DATA_SYSTEM_DEFAULTS = {
|
|
373
|
+
initialConnectionMode: 'one-shot',
|
|
374
|
+
backgroundConnectionMode: undefined,
|
|
375
|
+
automaticModeSwitching: false,
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* Default FDv2 data system configuration for mobile (React Native) SDKs.
|
|
379
|
+
*/
|
|
380
|
+
const MOBILE_DATA_SYSTEM_DEFAULTS = {
|
|
381
|
+
initialConnectionMode: 'streaming',
|
|
382
|
+
backgroundConnectionMode: 'background',
|
|
383
|
+
automaticModeSwitching: true,
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* Default FDv2 data system configuration for desktop SDKs (Electron, etc.).
|
|
387
|
+
*/
|
|
388
|
+
const DESKTOP_DATA_SYSTEM_DEFAULTS = {
|
|
389
|
+
initialConnectionMode: 'streaming',
|
|
390
|
+
backgroundConnectionMode: undefined,
|
|
391
|
+
automaticModeSwitching: false,
|
|
251
392
|
};
|
|
252
393
|
|
|
394
|
+
function createValidators(options) {
|
|
395
|
+
return {
|
|
396
|
+
logger: jsSdkCommon.TypeValidators.Object,
|
|
397
|
+
maxCachedContexts: jsSdkCommon.TypeValidators.numberWithMin(0),
|
|
398
|
+
baseUri: jsSdkCommon.TypeValidators.String,
|
|
399
|
+
streamUri: jsSdkCommon.TypeValidators.String,
|
|
400
|
+
eventsUri: jsSdkCommon.TypeValidators.String,
|
|
401
|
+
capacity: jsSdkCommon.TypeValidators.numberWithMin(1),
|
|
402
|
+
diagnosticRecordingInterval: jsSdkCommon.TypeValidators.numberWithMin(2),
|
|
403
|
+
flushInterval: jsSdkCommon.TypeValidators.numberWithMin(2),
|
|
404
|
+
streamInitialReconnectDelay: jsSdkCommon.TypeValidators.numberWithMin(0),
|
|
405
|
+
allAttributesPrivate: jsSdkCommon.TypeValidators.Boolean,
|
|
406
|
+
debug: jsSdkCommon.TypeValidators.Boolean,
|
|
407
|
+
diagnosticOptOut: jsSdkCommon.TypeValidators.Boolean,
|
|
408
|
+
withReasons: jsSdkCommon.TypeValidators.Boolean,
|
|
409
|
+
sendEvents: jsSdkCommon.TypeValidators.Boolean,
|
|
410
|
+
pollInterval: jsSdkCommon.TypeValidators.numberWithMin(30),
|
|
411
|
+
useReport: jsSdkCommon.TypeValidators.Boolean,
|
|
412
|
+
privateAttributes: jsSdkCommon.TypeValidators.StringArray,
|
|
413
|
+
disableCache: jsSdkCommon.TypeValidators.Boolean,
|
|
414
|
+
applicationInfo: jsSdkCommon.TypeValidators.Object,
|
|
415
|
+
wrapperName: jsSdkCommon.TypeValidators.String,
|
|
416
|
+
wrapperVersion: jsSdkCommon.TypeValidators.String,
|
|
417
|
+
payloadFilterKey: jsSdkCommon.TypeValidators.stringMatchingRegex(/^[a-zA-Z0-9](\w|\.|-)*$/),
|
|
418
|
+
hooks: jsSdkCommon.TypeValidators.createTypeArray('Hook[]', {}),
|
|
419
|
+
inspectors: jsSdkCommon.TypeValidators.createTypeArray('LDInspection', {}),
|
|
420
|
+
cleanOldPersistentData: jsSdkCommon.TypeValidators.Boolean,
|
|
421
|
+
dataSystem: options?.dataSystemDefaults
|
|
422
|
+
? validatorOf(dataSystemValidators, options.dataSystemDefaults)
|
|
423
|
+
: jsSdkCommon.TypeValidators.Object,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
253
427
|
const DEFAULT_POLLING_INTERVAL = 60 * 5;
|
|
254
428
|
const DEFAULT_POLLING = 'https://clientsdk.launchdarkly.com';
|
|
255
429
|
const DEFAULT_STREAM = 'https://clientstream.launchdarkly.com';
|
|
@@ -275,6 +449,7 @@ class ConfigurationImpl {
|
|
|
275
449
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
276
450
|
this.streamUri = DEFAULT_STREAM;
|
|
277
451
|
this.maxCachedContexts = 5;
|
|
452
|
+
this.disableCache = false;
|
|
278
453
|
this.capacity = 100;
|
|
279
454
|
this.diagnosticRecordingInterval = 900;
|
|
280
455
|
this.flushInterval = 30;
|
|
@@ -291,8 +466,15 @@ class ConfigurationImpl {
|
|
|
291
466
|
this.hooks = [];
|
|
292
467
|
this.inspectors = [];
|
|
293
468
|
this.logger = ensureSafeLogger(pristineOptions.logger);
|
|
294
|
-
const
|
|
295
|
-
|
|
469
|
+
const validators = createValidators({
|
|
470
|
+
dataSystemDefaults: internalOptions.dataSystemDefaults,
|
|
471
|
+
});
|
|
472
|
+
const validated = validateOptions(pristineOptions, validators, {}, this.logger);
|
|
473
|
+
Object.entries(validated).forEach(([k, v]) => {
|
|
474
|
+
if (k !== 'logger') {
|
|
475
|
+
this[k] = v;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
296
478
|
this.serviceEndpoints = new jsSdkCommon.ServiceEndpoints(this.streamUri, this.baseUri, this.eventsUri, internalOptions.analyticsEventPath, internalOptions.diagnosticEventPath, internalOptions.includeAuthorizationHeader, pristineOptions.payloadFilterKey);
|
|
297
479
|
this.useReport = pristineOptions.useReport ?? false;
|
|
298
480
|
this.tags = new jsSdkCommon.ApplicationTags({ application: this.applicationInfo, logger: this.logger });
|
|
@@ -301,44 +483,6 @@ class ConfigurationImpl {
|
|
|
301
483
|
this.credentialType = internalOptions.credentialType;
|
|
302
484
|
this.getImplementationHooks = internalOptions.getImplementationHooks;
|
|
303
485
|
}
|
|
304
|
-
_validateTypesAndNames(pristineOptions) {
|
|
305
|
-
const errors = [];
|
|
306
|
-
Object.entries(pristineOptions).forEach(([k, v]) => {
|
|
307
|
-
const validator = validators[k];
|
|
308
|
-
if (validator) {
|
|
309
|
-
if (!validator.is(v)) {
|
|
310
|
-
const validatorType = validator.getType();
|
|
311
|
-
if (validatorType === 'boolean') {
|
|
312
|
-
errors.push(jsSdkCommon.OptionMessages.wrongOptionTypeBoolean(k, typeof v));
|
|
313
|
-
this[k] = !!v;
|
|
314
|
-
}
|
|
315
|
-
else if (validatorType === 'boolean | undefined | null') {
|
|
316
|
-
errors.push(jsSdkCommon.OptionMessages.wrongOptionTypeBoolean(k, typeof v));
|
|
317
|
-
if (typeof v !== 'boolean' && typeof v !== 'undefined' && v !== null) {
|
|
318
|
-
this[k] = !!v;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
else if (validator instanceof jsSdkCommon.NumberWithMinimum && jsSdkCommon.TypeValidators.Number.is(v)) {
|
|
322
|
-
const { min } = validator;
|
|
323
|
-
errors.push(jsSdkCommon.OptionMessages.optionBelowMinimum(k, v, min));
|
|
324
|
-
this[k] = min;
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
errors.push(jsSdkCommon.OptionMessages.wrongOptionType(k, validator.getType(), typeof v));
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
else if (k === 'logger') ;
|
|
331
|
-
else {
|
|
332
|
-
// if an option is explicitly null, coerce to undefined
|
|
333
|
-
this[k] = v ?? undefined;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
337
|
-
errors.push(jsSdkCommon.OptionMessages.unknownOption(k));
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
return errors;
|
|
341
|
-
}
|
|
342
486
|
}
|
|
343
487
|
|
|
344
488
|
async function digest(hasher, encoding) {
|
|
@@ -677,6 +821,71 @@ class EventFactory extends jsSdkCommon.internal.EventFactoryBase {
|
|
|
677
821
|
}
|
|
678
822
|
}
|
|
679
823
|
|
|
824
|
+
/**
|
|
825
|
+
* Suffix appended to context storage keys to form the freshness storage key.
|
|
826
|
+
*/
|
|
827
|
+
const FRESHNESS_SUFFIX = '_freshness';
|
|
828
|
+
/**
|
|
829
|
+
* Computes a SHA-256 hash of the context's full canonical JSON.
|
|
830
|
+
* Returns `undefined` if the context cannot be serialized.
|
|
831
|
+
*/
|
|
832
|
+
async function hashContext(crypto, context) {
|
|
833
|
+
const json = context.canonicalUnfilteredJson();
|
|
834
|
+
if (!json) {
|
|
835
|
+
return undefined;
|
|
836
|
+
}
|
|
837
|
+
return digest(crypto.createHash('sha256').update(json), 'base64');
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function isValidFlag(value) {
|
|
841
|
+
return value !== null && typeof value === 'object' && typeof value.version === 'number';
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Loads cached flag data from storage for the given context.
|
|
845
|
+
*
|
|
846
|
+
* Checks the current storage key first, then falls back to the legacy
|
|
847
|
+
* canonical key location (pre-10.3.1). Does NOT perform migration — the
|
|
848
|
+
* caller is responsible for migrating data if {@link CachedFlagData.fromLegacyKey}
|
|
849
|
+
* is true.
|
|
850
|
+
*
|
|
851
|
+
* @returns The cached flag data, or `undefined` on cache miss or parse error.
|
|
852
|
+
*/
|
|
853
|
+
async function loadCachedFlags(storage, crypto, environmentNamespace, context, logger) {
|
|
854
|
+
const storageKey = await namespaceForContextData(crypto, environmentNamespace, context);
|
|
855
|
+
let flagsJson = await storage.get(storageKey);
|
|
856
|
+
let fromLegacyKey = false;
|
|
857
|
+
if (flagsJson === null || flagsJson === undefined) {
|
|
858
|
+
// Fallback: in version <10.3.1 flag data was stored under the canonical key.
|
|
859
|
+
flagsJson = await storage.get(context.canonicalKey);
|
|
860
|
+
if (flagsJson === null || flagsJson === undefined) {
|
|
861
|
+
return undefined;
|
|
862
|
+
}
|
|
863
|
+
fromLegacyKey = true;
|
|
864
|
+
}
|
|
865
|
+
try {
|
|
866
|
+
const parsed = JSON.parse(flagsJson);
|
|
867
|
+
if (parsed === null || typeof parsed !== 'object') {
|
|
868
|
+
logger?.warn('Cached flag data is not a valid object');
|
|
869
|
+
return undefined;
|
|
870
|
+
}
|
|
871
|
+
const entries = Object.entries(parsed);
|
|
872
|
+
const invalidKey = entries.find(([, value]) => !isValidFlag(value));
|
|
873
|
+
if (invalidKey) {
|
|
874
|
+
logger?.warn(`Discarding cached flags due to invalid entry: ${invalidKey[0]}`);
|
|
875
|
+
return undefined;
|
|
876
|
+
}
|
|
877
|
+
const flags = entries.reduce((acc, [key, value]) => {
|
|
878
|
+
acc[key] = value;
|
|
879
|
+
return acc;
|
|
880
|
+
}, {});
|
|
881
|
+
return { flags, storageKey, fromLegacyKey };
|
|
882
|
+
}
|
|
883
|
+
catch (e) {
|
|
884
|
+
logger?.warn(`Could not parse cached flag evaluations from persistent storage: ${e.message}`);
|
|
885
|
+
return undefined;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
680
889
|
/**
|
|
681
890
|
* An index for tracking the most recently used contexts by timestamp with the ability to
|
|
682
891
|
* update entry timestamps and prune out least used contexts above a max capacity provided.
|
|
@@ -742,12 +951,18 @@ class ContextIndex {
|
|
|
742
951
|
* This class handles persisting and loading flag values from a persistent
|
|
743
952
|
* store. It intercepts updates and forwards them to the flag updater and
|
|
744
953
|
* then persists changes after the updater has completed.
|
|
954
|
+
*
|
|
955
|
+
* Freshness metadata (timestamp + context attribute hash) is stored in a
|
|
956
|
+
* separate storage key (`{contextKey}_freshness`) alongside the flag data.
|
|
957
|
+
* Both keys are managed together — when a context is evicted, both the flag
|
|
958
|
+
* data and freshness record are cleared.
|
|
745
959
|
*/
|
|
746
960
|
class FlagPersistence {
|
|
747
|
-
constructor(_platform, _environmentNamespace, _maxCachedContexts, _flagStore, _flagUpdater, _logger, _timeStamper = () => Date.now()) {
|
|
961
|
+
constructor(_platform, _environmentNamespace, _maxCachedContexts, _disableCache, _flagStore, _flagUpdater, _logger, _timeStamper = () => Date.now()) {
|
|
748
962
|
this._platform = _platform;
|
|
749
963
|
this._environmentNamespace = _environmentNamespace;
|
|
750
964
|
this._maxCachedContexts = _maxCachedContexts;
|
|
965
|
+
this._disableCache = _disableCache;
|
|
751
966
|
this._flagStore = _flagStore;
|
|
752
967
|
this._flagUpdater = _flagUpdater;
|
|
753
968
|
this._logger = _logger;
|
|
@@ -779,35 +994,38 @@ class FlagPersistence {
|
|
|
779
994
|
* {@link FlagUpdater} this {@link FlagPersistence} was constructed with.
|
|
780
995
|
*/
|
|
781
996
|
async loadCached(context) {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
if (flagsJson === null || flagsJson === undefined) {
|
|
785
|
-
// Fallback: in version <10.3.1 flag data was stored under the canonical key, check
|
|
786
|
-
// to see if data is present and migrate the data if present.
|
|
787
|
-
flagsJson = await this._platform.storage?.get(context.canonicalKey);
|
|
788
|
-
if (flagsJson === null || flagsJson === undefined) {
|
|
789
|
-
// return false indicating cache did not load if flag json is still absent
|
|
790
|
-
return false;
|
|
791
|
-
}
|
|
792
|
-
// migrate data from version <10.3.1 and cleanup data that was under canonical key
|
|
793
|
-
await this._platform.storage?.set(storageKey, flagsJson);
|
|
794
|
-
await this._platform.storage?.clear(context.canonicalKey);
|
|
997
|
+
if (this._disableCache || this._maxCachedContexts <= 0) {
|
|
998
|
+
return false;
|
|
795
999
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
// mapping flags to item descriptors
|
|
799
|
-
const descriptors = Object.entries(flags).reduce((acc, [key, flag]) => {
|
|
800
|
-
acc[key] = { version: flag.version, flag };
|
|
801
|
-
return acc;
|
|
802
|
-
}, {});
|
|
803
|
-
this._flagUpdater.initCached(context, descriptors);
|
|
804
|
-
this._logger.debug('Loaded cached flag evaluations from persistent storage');
|
|
805
|
-
return true;
|
|
1000
|
+
if (!this._platform.storage) {
|
|
1001
|
+
return false;
|
|
806
1002
|
}
|
|
807
|
-
|
|
808
|
-
|
|
1003
|
+
const cached = await loadCachedFlags(this._platform.storage, this._platform.crypto, this._environmentNamespace, context, this._logger);
|
|
1004
|
+
if (!cached) {
|
|
809
1005
|
return false;
|
|
810
1006
|
}
|
|
1007
|
+
// Migrate data from version <10.3.1 stored under the canonical key
|
|
1008
|
+
if (cached.fromLegacyKey) {
|
|
1009
|
+
await this._platform.storage.set(cached.storageKey, JSON.stringify(cached.flags));
|
|
1010
|
+
await this._platform.storage.clear(context.canonicalKey);
|
|
1011
|
+
}
|
|
1012
|
+
// mapping flags to item descriptors
|
|
1013
|
+
const descriptors = Object.entries(cached.flags).reduce((acc, [key, flag]) => {
|
|
1014
|
+
acc[key] = { version: flag.version, flag };
|
|
1015
|
+
return acc;
|
|
1016
|
+
}, {});
|
|
1017
|
+
this._flagUpdater.initCached(context, descriptors);
|
|
1018
|
+
this._logger.debug('Loaded cached flag evaluations from persistent storage');
|
|
1019
|
+
return true;
|
|
1020
|
+
}
|
|
1021
|
+
async _storeFreshness(contextStorageKey, context, timestamp) {
|
|
1022
|
+
const contextHash = await hashContext(this._platform.crypto, context);
|
|
1023
|
+
if (contextHash === undefined) {
|
|
1024
|
+
this._logger.error('Could not serialize context for freshness tracking');
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
const record = { timestamp, contextHash };
|
|
1028
|
+
await this._platform.storage?.set(`${contextStorageKey}${FRESHNESS_SUFFIX}`, JSON.stringify(record));
|
|
811
1029
|
}
|
|
812
1030
|
async _loadIndex() {
|
|
813
1031
|
if (this._contextIndex !== undefined) {
|
|
@@ -829,13 +1047,26 @@ class FlagPersistence {
|
|
|
829
1047
|
return this._contextIndex;
|
|
830
1048
|
}
|
|
831
1049
|
async _storeCache(context) {
|
|
1050
|
+
if (this._disableCache) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const now = this._timeStamper();
|
|
832
1054
|
const index = await this._loadIndex();
|
|
833
1055
|
const storageKey = await namespaceForContextData(this._platform.crypto, this._environmentNamespace, context);
|
|
834
|
-
|
|
1056
|
+
if (this._maxCachedContexts > 0) {
|
|
1057
|
+
index.notice(storageKey, now);
|
|
1058
|
+
}
|
|
835
1059
|
const pruned = index.prune(this._maxCachedContexts);
|
|
836
|
-
|
|
837
|
-
|
|
1060
|
+
// If maxCachedContexts <= 0, current context was never added, so always skip flag write
|
|
1061
|
+
const currentContextWasPruned = this._maxCachedContexts <= 0 || pruned.some((it) => it.id === storageKey);
|
|
1062
|
+
await Promise.all(pruned.flatMap((it) => [
|
|
1063
|
+
this._platform.storage?.clear(it.id),
|
|
1064
|
+
this._platform.storage?.clear(`${it.id}${FRESHNESS_SUFFIX}`),
|
|
1065
|
+
]));
|
|
838
1066
|
await this._platform.storage?.set(await this._indexKeyPromise, index.toJson());
|
|
1067
|
+
if (currentContextWasPruned) {
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
839
1070
|
const allFlags = this._flagStore.getAll();
|
|
840
1071
|
// mapping item descriptors to flags
|
|
841
1072
|
const flags = Object.entries(allFlags).reduce((acc, [key, descriptor]) => {
|
|
@@ -845,8 +1076,15 @@ class FlagPersistence {
|
|
|
845
1076
|
return acc;
|
|
846
1077
|
}, {});
|
|
847
1078
|
const jsonAll = JSON.stringify(flags);
|
|
848
|
-
// store flag data
|
|
1079
|
+
// store flag data first, so freshness is never newer than the flags it describes
|
|
849
1080
|
await this._platform.storage?.set(storageKey, jsonAll);
|
|
1081
|
+
// store freshness — best-effort, must not block flag persistence
|
|
1082
|
+
try {
|
|
1083
|
+
await this._storeFreshness(storageKey, context, now);
|
|
1084
|
+
}
|
|
1085
|
+
catch (e) {
|
|
1086
|
+
this._logger.warn(`Failed to store freshness data: ${e.message}`);
|
|
1087
|
+
}
|
|
850
1088
|
}
|
|
851
1089
|
}
|
|
852
1090
|
|
|
@@ -962,17 +1200,18 @@ class DefaultFlagManager {
|
|
|
962
1200
|
* @param platform implementation of various platform provided functionality
|
|
963
1201
|
* @param sdkKey that will be used to distinguish different environments
|
|
964
1202
|
* @param maxCachedContexts that specifies the max number of contexts that will be cached in persistence
|
|
1203
|
+
* @param disableCache set to true to completely disable the persistent flag cache
|
|
965
1204
|
* @param logger used for logging various messages
|
|
966
1205
|
* @param timeStamper exists for testing purposes
|
|
967
1206
|
*/
|
|
968
|
-
constructor(platform, sdkKey, maxCachedContexts, logger, timeStamper = () => Date.now()) {
|
|
1207
|
+
constructor(platform, sdkKey, maxCachedContexts, disableCache, logger, timeStamper = () => Date.now()) {
|
|
969
1208
|
this._flagStore = createDefaultFlagStore();
|
|
970
1209
|
this._flagUpdater = createFlagUpdater(this._flagStore, logger);
|
|
971
|
-
this._flagPersistencePromise = this._initPersistence(platform, sdkKey, maxCachedContexts, logger, timeStamper);
|
|
1210
|
+
this._flagPersistencePromise = this._initPersistence(platform, sdkKey, maxCachedContexts, disableCache, logger, timeStamper);
|
|
972
1211
|
}
|
|
973
|
-
async _initPersistence(platform, sdkKey, maxCachedContexts, logger, timeStamper = () => Date.now()) {
|
|
1212
|
+
async _initPersistence(platform, sdkKey, maxCachedContexts, disableCache, logger, timeStamper = () => Date.now()) {
|
|
974
1213
|
const environmentNamespace = await namespaceForEnvironment(platform.crypto, sdkKey);
|
|
975
|
-
return new FlagPersistence(platform, environmentNamespace, maxCachedContexts, this._flagStore, this._flagUpdater, logger, timeStamper);
|
|
1214
|
+
return new FlagPersistence(platform, environmentNamespace, maxCachedContexts, disableCache, this._flagStore, this._flagUpdater, logger, timeStamper);
|
|
976
1215
|
}
|
|
977
1216
|
get(key) {
|
|
978
1217
|
if (this._overrides && Object.prototype.hasOwnProperty.call(this._overrides, key)) {
|
|
@@ -1448,7 +1687,7 @@ class LDClientImpl {
|
|
|
1448
1687
|
this._config = new ConfigurationImpl(options, internalOptions);
|
|
1449
1688
|
this.logger = this._config.logger;
|
|
1450
1689
|
this._baseHeaders = jsSdkCommon.defaultHeaders(this.sdkKey, this.platform.info, this._config.tags, this._config.serviceEndpoints.includeAuthorizationHeader, this._config.userAgentHeaderName);
|
|
1451
|
-
this._flagManager = new DefaultFlagManager(this.platform, sdkKey, this._config.maxCachedContexts, this._config.logger);
|
|
1690
|
+
this._flagManager = new DefaultFlagManager(this.platform, sdkKey, this._config.maxCachedContexts, this._config.disableCache ?? false, this._config.logger);
|
|
1452
1691
|
this._diagnosticsManager = createDiagnosticsManager(sdkKey, this._config, platform);
|
|
1453
1692
|
this._eventProcessor = createEventProcessor(sdkKey, this._config, platform, this._baseHeaders, this._diagnosticsManager);
|
|
1454
1693
|
this.emitter = new LDEmitter();
|
|
@@ -2542,16 +2781,88 @@ class BaseDataManager {
|
|
|
2542
2781
|
}
|
|
2543
2782
|
}
|
|
2544
2783
|
|
|
2784
|
+
function allConditionsMatch(conditions, input) {
|
|
2785
|
+
return Object.entries(conditions).every(([key, value]) => value === undefined || input[key] === value);
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* Given a mode resolution table and the current input state, returns the
|
|
2789
|
+
* resolved FDv2 connection mode.
|
|
2790
|
+
*
|
|
2791
|
+
* Iterates entries in order. The first entry whose conditions all match the
|
|
2792
|
+
* input wins. If no entry matches (should not happen when the table ends with
|
|
2793
|
+
* a catch-all), falls back to `input.foregroundMode`.
|
|
2794
|
+
*/
|
|
2795
|
+
const CONFIGURED_MODE_MAP = {
|
|
2796
|
+
foreground: 'foregroundMode',
|
|
2797
|
+
background: 'backgroundMode',
|
|
2798
|
+
};
|
|
2799
|
+
function resolveConnectionMode(table, input) {
|
|
2800
|
+
const match = table.find((entry) => allConditionsMatch(entry.conditions, input));
|
|
2801
|
+
if (match) {
|
|
2802
|
+
const { mode } = match;
|
|
2803
|
+
if (typeof mode === 'object') {
|
|
2804
|
+
return input[CONFIGURED_MODE_MAP[mode.configured]];
|
|
2805
|
+
}
|
|
2806
|
+
return mode;
|
|
2807
|
+
}
|
|
2808
|
+
return input.foregroundMode;
|
|
2809
|
+
}
|
|
2810
|
+
/**
|
|
2811
|
+
* Mode resolution table for mobile platforms (React Native, etc.).
|
|
2812
|
+
*
|
|
2813
|
+
* - No network → offline.
|
|
2814
|
+
* - Background → configured background mode.
|
|
2815
|
+
* - Foreground → configured foreground mode.
|
|
2816
|
+
*/
|
|
2817
|
+
const MOBILE_TRANSITION_TABLE = [
|
|
2818
|
+
{ conditions: { networkAvailable: false }, mode: 'offline' },
|
|
2819
|
+
{ conditions: { lifecycle: 'background' }, mode: { configured: 'background' } },
|
|
2820
|
+
{ conditions: { lifecycle: 'foreground' }, mode: { configured: 'foreground' } },
|
|
2821
|
+
];
|
|
2822
|
+
/**
|
|
2823
|
+
* Mode resolution table for browser platforms.
|
|
2824
|
+
*
|
|
2825
|
+
* - No network → offline.
|
|
2826
|
+
* - Otherwise → configured foreground mode.
|
|
2827
|
+
*
|
|
2828
|
+
* Browser listener-driven streaming (auto-promotion to streaming when change
|
|
2829
|
+
* listeners are registered) is handled externally by the caller modifying
|
|
2830
|
+
* `foregroundMode` before consulting this table.
|
|
2831
|
+
*/
|
|
2832
|
+
const BROWSER_TRANSITION_TABLE = [
|
|
2833
|
+
{ conditions: { networkAvailable: false }, mode: 'offline' },
|
|
2834
|
+
{ conditions: {}, mode: { configured: 'foreground' } },
|
|
2835
|
+
];
|
|
2836
|
+
/**
|
|
2837
|
+
* Mode resolution table for desktop platforms (Electron, etc.).
|
|
2838
|
+
*
|
|
2839
|
+
* - No network → offline.
|
|
2840
|
+
* - Otherwise → configured foreground mode.
|
|
2841
|
+
*/
|
|
2842
|
+
const DESKTOP_TRANSITION_TABLE = [
|
|
2843
|
+
{ conditions: { networkAvailable: false }, mode: 'offline' },
|
|
2844
|
+
{ conditions: {}, mode: { configured: 'foreground' } },
|
|
2845
|
+
];
|
|
2846
|
+
|
|
2545
2847
|
exports.platform = jsSdkCommon__namespace;
|
|
2848
|
+
exports.BROWSER_DATA_SYSTEM_DEFAULTS = BROWSER_DATA_SYSTEM_DEFAULTS;
|
|
2849
|
+
exports.BROWSER_TRANSITION_TABLE = BROWSER_TRANSITION_TABLE;
|
|
2546
2850
|
exports.BaseDataManager = BaseDataManager;
|
|
2851
|
+
exports.DESKTOP_DATA_SYSTEM_DEFAULTS = DESKTOP_DATA_SYSTEM_DEFAULTS;
|
|
2852
|
+
exports.DESKTOP_TRANSITION_TABLE = DESKTOP_TRANSITION_TABLE;
|
|
2547
2853
|
exports.DataSourceState = DataSourceState;
|
|
2548
2854
|
exports.LDClientImpl = LDClientImpl;
|
|
2855
|
+
exports.MOBILE_DATA_SYSTEM_DEFAULTS = MOBILE_DATA_SYSTEM_DEFAULTS;
|
|
2856
|
+
exports.MOBILE_TRANSITION_TABLE = MOBILE_TRANSITION_TABLE;
|
|
2549
2857
|
exports.browserFdv1Endpoints = browserFdv1Endpoints;
|
|
2858
|
+
exports.dataSystemValidators = dataSystemValidators;
|
|
2550
2859
|
exports.fdv2Endpoints = fdv2Endpoints;
|
|
2551
2860
|
exports.makeRequestor = makeRequestor;
|
|
2552
2861
|
exports.mobileFdv1Endpoints = mobileFdv1Endpoints;
|
|
2553
2862
|
exports.readFlagsFromBootstrap = readFlagsFromBootstrap;
|
|
2863
|
+
exports.resolveConnectionMode = resolveConnectionMode;
|
|
2554
2864
|
exports.safeRegisterDebugOverridePlugins = safeRegisterDebugOverridePlugins;
|
|
2865
|
+
exports.validateOptions = validateOptions;
|
|
2555
2866
|
Object.keys(jsSdkCommon).forEach(function (k) {
|
|
2556
2867
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
2557
2868
|
enumerable: true,
|