launchdarkly-js-sdk-common
Advanced tools
Comparing version 5.2.0 to 5.3.0
@@ -5,2 +5,20 @@ # Change log | ||
## [5.3.0](https://github.com/launchdarkly/js-sdk-common/compare/launchdarkly-js-sdk-common-v5.2.0...launchdarkly-js-sdk-common-v5.3.0) (2024-06-18) | ||
### Features | ||
* Add inExperiment to evaluation reason. ([#105](https://github.com/launchdarkly/js-sdk-common/issues/105)) ([cf69770](https://github.com/launchdarkly/js-sdk-common/commit/cf6977080e67e4e54f773df410a671764dbcb304)) | ||
* Allow for synchronous inspectors. ([#103](https://github.com/launchdarkly/js-sdk-common/issues/103)) ([7e490f4](https://github.com/launchdarkly/js-sdk-common/commit/7e490f479299f772a9db78efd1c2235645785250)) | ||
## [5.2.0] - 2024-05-01 | ||
### Added: | ||
- Added an optional timeout to the `waitForInitialization` method. When a timeout is specified the returned promise will be rejected after the timeout elapses if the client has not finished initializing within that time. When no timeout is specified the returned promise will not be resolved or rejected until the initialization either completes or fails. | ||
### Changed: | ||
- The track method now validates that the provided metricValue is a number. If a metric value is provided, and it is not a number, then a warning will be logged. | ||
### Fixed: | ||
- Fixed the documentation for `evaluationReasons` for the `identify` method. | ||
## [5.1.0] - 2024-03-19 | ||
@@ -7,0 +25,0 @@ ### Changed: |
{ | ||
"name": "launchdarkly-js-sdk-common", | ||
"version": "5.2.0", | ||
"version": "5.3.0", | ||
"description": "LaunchDarkly SDK for JavaScript - common code", | ||
@@ -20,3 +20,4 @@ "author": "LaunchDarkly <team@launchdarkly.com>", | ||
"test": "cross-env NODE_ENV=test jest", | ||
"check-typescript": "node_modules/typescript/bin/tsc" | ||
"check-typescript": "tsc", | ||
"doc": "typedoc" | ||
}, | ||
@@ -47,3 +48,4 @@ "devDependencies": { | ||
"readline-sync": "^1.4.9", | ||
"typescript": "~4.4.4" | ||
"typescript": "~5.4.5", | ||
"typedoc": "^0.25.13" | ||
}, | ||
@@ -50,0 +52,0 @@ "dependencies": { |
# LaunchDarkly Javascript SDK Core Components | ||
[](https://circleci.com/gh/launchdarkly/js-sdk-common/tree/master) | ||
[![Actions Status][ci-badge]][ci] | ||
@@ -36,1 +36,4 @@ ## LaunchDarkly overview | ||
* [blog.launchdarkly.com](https://blog.launchdarkly.com/ "LaunchDarkly Blog Documentation") for the latest product updates | ||
[ci-badge]: https://github.com/launchdarkly/js-sdk-common/actions/workflows/ci.yml/badge.svg | ||
[ci]: https://github.com/launchdarkly/js-sdk-common/actions/workflows/ci.yml |
@@ -31,3 +31,3 @@ const { AsyncQueue } = require('launchdarkly-js-test-helpers'); | ||
describe('given an inspector with callbacks of every type', () => { | ||
describe.each([true, false])('given an inspector with callbacks of every type: synchronous: %p', synchronous => { | ||
/** | ||
@@ -43,2 +43,3 @@ * @type {AsyncQueue} | ||
name: 'my-flag-used-inspector', | ||
synchronous, | ||
method: (flagKey, flagDetail, context) => { | ||
@@ -52,2 +53,3 @@ eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context }); | ||
name: 'my-other-flag-used-inspector', | ||
synchronous, | ||
method: (flagKey, flagDetail, context) => { | ||
@@ -60,2 +62,3 @@ eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context }); | ||
name: 'my-flag-details-inspector', | ||
synchronous, | ||
method: details => { | ||
@@ -71,2 +74,3 @@ eventQueue.add({ | ||
name: 'my-flag-detail-inspector', | ||
synchronous, | ||
method: (flagKey, flagDetail) => { | ||
@@ -83,2 +87,3 @@ eventQueue.add({ | ||
name: 'my-identity-inspector', | ||
synchronous, | ||
method: context => { | ||
@@ -94,2 +99,3 @@ eventQueue.add({ | ||
type: 'potato', | ||
synchronous, | ||
name: 'my-potato-inspector', | ||
@@ -96,0 +102,0 @@ method: () => {}, |
@@ -8,3 +8,3 @@ const { AsyncQueue } = require('launchdarkly-js-test-helpers'); | ||
describe('given a streaming client with registered inspectors', () => { | ||
describe.each([true, false])('given a streaming client with registered inspectors, synchronous: %p', synchronous => { | ||
const eventQueue = new AsyncQueue(); | ||
@@ -15,2 +15,3 @@ | ||
type: 'flag-used', | ||
synchronous, | ||
method: (flagKey, flagDetail, context) => { | ||
@@ -23,2 +24,3 @@ eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context }); | ||
type: 'flag-used', | ||
synchronous, | ||
method: (flagKey, flagDetail, context) => { | ||
@@ -30,2 +32,3 @@ eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context }); | ||
type: 'flag-details-changed', | ||
synchronous, | ||
method: details => { | ||
@@ -40,2 +43,3 @@ eventQueue.add({ | ||
type: 'flag-detail-changed', | ||
synchronous, | ||
method: (flagKey, flagDetail) => { | ||
@@ -51,2 +55,3 @@ eventQueue.add({ | ||
type: 'client-identity-changed', | ||
synchronous, | ||
method: context => { | ||
@@ -53,0 +58,0 @@ eventQueue.add({ |
@@ -465,4 +465,4 @@ const EventProcessor = require('./EventProcessor'); | ||
} | ||
notifyInspectionFlagChanged(data, newFlag); | ||
handleFlagChanges(mods); // don't wait for this Promise to be resolved | ||
notifyInspectionFlagChanged(data, newFlag); | ||
} else { | ||
@@ -469,0 +469,0 @@ logger.debug(messages.debugStreamPatchIgnored(data.key)); |
@@ -25,2 +25,5 @@ const messages = require('./messages'); | ||
* Collection of inspectors keyed by type. | ||
* | ||
* Inspectors are async by default. | ||
* | ||
* @type {{[type: string]: object[]}} | ||
@@ -34,2 +37,13 @@ */ | ||
}; | ||
/** | ||
* Collection synchronous of inspectors keyed by type. | ||
* | ||
* @type {{[type: string]: object[]}} | ||
*/ | ||
const synchronousInspectorsByType = { | ||
[InspectorTypes.flagUsed]: [], | ||
[InspectorTypes.flagDetailsChanged]: [], | ||
[InspectorTypes.flagDetailChanged]: [], | ||
[InspectorTypes.clientIdentityChanged]: [], | ||
}; | ||
@@ -41,4 +55,9 @@ const safeInspectors = inspectors && inspectors.map(inspector => SafeInspector(inspector, logger)); | ||
// Only add inspectors of supported types. | ||
if (Object.prototype.hasOwnProperty.call(inspectorsByType, safeInspector.type)) { | ||
if (Object.prototype.hasOwnProperty.call(inspectorsByType, safeInspector.type) && !safeInspector.synchronous) { | ||
inspectorsByType[safeInspector.type].push(safeInspector); | ||
} else if ( | ||
Object.prototype.hasOwnProperty.call(synchronousInspectorsByType, safeInspector.type) && | ||
safeInspector.synchronous | ||
) { | ||
synchronousInspectorsByType[safeInspector.type].push(safeInspector); | ||
} else { | ||
@@ -55,3 +74,5 @@ logger.warn(messages.invalidInspector(safeInspector.type, safeInspector.name)); | ||
*/ | ||
manager.hasListeners = type => inspectorsByType[type] && inspectorsByType[type].length; | ||
manager.hasListeners = type => | ||
(inspectorsByType[type] && inspectorsByType[type].length) || | ||
(synchronousInspectorsByType[type] && synchronousInspectorsByType[type].length); | ||
@@ -68,5 +89,9 @@ /** | ||
manager.onFlagUsed = (flagKey, detail, context) => { | ||
if (inspectorsByType[InspectorTypes.flagUsed].length) { | ||
const type = InspectorTypes.flagUsed; | ||
if (synchronousInspectorsByType[type].length) { | ||
synchronousInspectorsByType[type].forEach(inspector => inspector.method(flagKey, detail, context)); | ||
} | ||
if (inspectorsByType[type].length) { | ||
onNextTick(() => { | ||
inspectorsByType[InspectorTypes.flagUsed].forEach(inspector => inspector.method(flagKey, detail, context)); | ||
inspectorsByType[type].forEach(inspector => inspector.method(flagKey, detail, context)); | ||
}); | ||
@@ -84,5 +109,9 @@ } | ||
manager.onFlags = flags => { | ||
if (inspectorsByType[InspectorTypes.flagDetailsChanged].length) { | ||
const type = InspectorTypes.flagDetailsChanged; | ||
if (synchronousInspectorsByType[type].length) { | ||
synchronousInspectorsByType[type].forEach(inspector => inspector.method(flags)); | ||
} | ||
if (inspectorsByType[type].length) { | ||
onNextTick(() => { | ||
inspectorsByType[InspectorTypes.flagDetailsChanged].forEach(inspector => inspector.method(flags)); | ||
inspectorsByType[type].forEach(inspector => inspector.method(flags)); | ||
}); | ||
@@ -101,5 +130,9 @@ } | ||
manager.onFlagChanged = (flagKey, flag) => { | ||
if (inspectorsByType[InspectorTypes.flagDetailChanged].length) { | ||
const type = InspectorTypes.flagDetailChanged; | ||
if (synchronousInspectorsByType[type].length) { | ||
synchronousInspectorsByType[type].forEach(inspector => inspector.method(flagKey, flag)); | ||
} | ||
if (inspectorsByType[type].length) { | ||
onNextTick(() => { | ||
inspectorsByType[InspectorTypes.flagDetailChanged].forEach(inspector => inspector.method(flagKey, flag)); | ||
inspectorsByType[type].forEach(inspector => inspector.method(flagKey, flag)); | ||
}); | ||
@@ -117,5 +150,9 @@ } | ||
manager.onIdentityChanged = context => { | ||
if (inspectorsByType[InspectorTypes.clientIdentityChanged].length) { | ||
const type = InspectorTypes.clientIdentityChanged; | ||
if (synchronousInspectorsByType[type].length) { | ||
synchronousInspectorsByType[type].forEach(inspector => inspector.method(context)); | ||
} | ||
if (inspectorsByType[type].length) { | ||
onNextTick(() => { | ||
inspectorsByType[InspectorTypes.clientIdentityChanged].forEach(inspector => inspector.method(context)); | ||
inspectorsByType[type].forEach(inspector => inspector.method(context)); | ||
}); | ||
@@ -122,0 +159,0 @@ } |
@@ -18,3 +18,3 @@ const errors = require('./errors'); | ||
const docLink = | ||
' Please see https://docs.launchdarkly.com/sdk/client-side/javascript#initializing-the-client for instructions on SDK initialization.'; | ||
' Please see https://docs.launchdarkly.com/sdk/client-side/javascript#initialize-the-client for instructions on SDK initialization.'; | ||
@@ -21,0 +21,0 @@ const clientNotReady = function() { |
@@ -12,2 +12,3 @@ const messages = require('./messages'); | ||
name: inspector.name, | ||
synchronous: inspector.synchronous, | ||
}; | ||
@@ -14,0 +15,0 @@ |
@@ -591,2 +591,10 @@ /** | ||
prerequisiteKey?: string; | ||
/** | ||
* Whether the evaluation was part of an experiment. | ||
* | ||
* This is true if the evaluation resulted in an experiment rollout and served one of | ||
* the variations in the experiment. Otherwise it is false or undefined. | ||
*/ | ||
inExperiment?: boolean; | ||
} | ||
@@ -1018,2 +1026,9 @@ | ||
/** | ||
* If `true`, then the inspector will be ran synchronously with evaluation. | ||
* Synchronous inspectors execute inline with evaluation and care should be taken to ensure | ||
* they have minimal performance overhead. | ||
*/ | ||
synchronous?: boolean, | ||
/** | ||
* This method is called when a flag is accessed via a variation method, or it can be called based on actions in | ||
@@ -1046,2 +1061,7 @@ * wrapper SDKs which have different methods of tracking when a flag was accessed. It is not called when a call is made | ||
/** | ||
* If `true`, then the inspector will be ran synchronously with flag updates. | ||
*/ | ||
synchronous?: boolean, | ||
/** | ||
* This method is called when the flags in the store are replaced with new flags. It will contain all flags | ||
@@ -1072,2 +1092,7 @@ * regardless of if they have been evaluated. | ||
/** | ||
* If `true`, then the inspector will be ran synchronously with flag updates. | ||
*/ | ||
synchronous?: boolean, | ||
/** | ||
* This method is called when a flag is updated. It will not be called | ||
@@ -1096,2 +1121,7 @@ * when all flags are updated. | ||
/** | ||
* If `true`, then the inspector will be ran synchronously with identification. | ||
*/ | ||
synchronous?: boolean, | ||
/** | ||
* This method will be called when an identify operation completes. | ||
@@ -1098,0 +1128,0 @@ */ |
Sorry, the diff of this file is not supported yet
451571
86
10579
39
25