@launchdarkly/js-sdk-common 2.24.3 → 2.25.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 +14 -0
- package/dist/cjs/api/subsystem/DataSystem/DataSource.d.ts +0 -15
- package/dist/cjs/api/subsystem/DataSystem/DataSource.d.ts.map +1 -1
- package/dist/cjs/datasource/CompositeDataSource.d.ts +1 -0
- package/dist/cjs/datasource/CompositeDataSource.d.ts.map +1 -1
- package/dist/cjs/index.cjs +58 -12
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/utils/http.d.ts +2 -1
- package/dist/cjs/utils/http.d.ts.map +1 -1
- package/dist/esm/api/subsystem/DataSystem/DataSource.d.ts +0 -15
- package/dist/esm/api/subsystem/DataSystem/DataSource.d.ts.map +1 -1
- package/dist/esm/datasource/CompositeDataSource.d.ts +1 -0
- package/dist/esm/datasource/CompositeDataSource.d.ts.map +1 -1
- package/dist/esm/index.mjs +58 -12
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/utils/http.d.ts +2 -1
- package/dist/esm/utils/http.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@launchdarkly/js-sdk-common` will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
|
|
4
4
|
|
|
5
|
+
## [2.25.0](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.24.4...js-sdk-common-v2.25.0) (2026-05-21)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add X-LaunchDarkly-Instance-Id header to server-node SDK (SDK-2358) ([#1377](https://github.com/launchdarkly/js-core/issues/1377)) ([814dc0b](https://github.com/launchdarkly/js-core/commit/814dc0bfd6b152385f3a758f9eeca37a0f9f08e8))
|
|
11
|
+
|
|
12
|
+
## [2.24.4](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.24.3...js-sdk-common-v2.24.4) (2026-05-06)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **server-node:** honor x-ld-fd-fallback directive in FDv2 initializer phase ([#1342](https://github.com/launchdarkly/js-core/issues/1342)) ([a80eaca](https://github.com/launchdarkly/js-core/commit/a80eacaafa6174e5f1b4fe21ba11534fdf1f92a8))
|
|
18
|
+
|
|
5
19
|
## [2.24.3](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.24.2...js-sdk-common-v2.24.3) (2026-04-30)
|
|
6
20
|
|
|
7
21
|
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @experimental
|
|
3
|
-
* This feature is not stable and not subject to any backwards compatibility guarantees or semantic
|
|
4
|
-
* versioning. It is not suitable for production usage.
|
|
5
|
-
*/
|
|
6
1
|
export declare enum DataSourceState {
|
|
7
2
|
Valid = 0,
|
|
8
3
|
Initializing = 1,
|
|
9
4
|
Interrupted = 2,
|
|
10
5
|
Closed = 3
|
|
11
6
|
}
|
|
12
|
-
/**
|
|
13
|
-
* @experimental
|
|
14
|
-
* This feature is not stable and not subject to any backwards compatibility guarantees or semantic
|
|
15
|
-
* versioning. It is not suitable for production usage.
|
|
16
|
-
*/
|
|
17
7
|
export interface DataSource {
|
|
18
8
|
/**
|
|
19
9
|
* May be called any number of times, if already started, has no effect
|
|
@@ -28,10 +18,5 @@ export interface DataSource {
|
|
|
28
18
|
*/
|
|
29
19
|
stop(): void;
|
|
30
20
|
}
|
|
31
|
-
/**
|
|
32
|
-
* @experimental
|
|
33
|
-
* This feature is not stable and not subject to any backwards compatibility guarantees or semantic
|
|
34
|
-
* versioning. It is not suitable for production usage.
|
|
35
|
-
*/
|
|
36
21
|
export type LDDataSourceFactory = () => DataSource;
|
|
37
22
|
//# sourceMappingURL=DataSource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataSource.d.ts","sourceRoot":"","sources":["../../../../src/api/subsystem/DataSystem/DataSource.ts"],"names":[],"mappings":"AACA
|
|
1
|
+
{"version":3,"file":"DataSource.d.ts","sourceRoot":"","sources":["../../../../src/api/subsystem/DataSystem/DataSource.ts"],"names":[],"mappings":"AACA,oBAAY,eAAe;IAEzB,KAAK,IAAA;IAEL,YAAY,IAAA;IAEZ,WAAW,IAAA;IAEX,MAAM,IAAA;CACP;AAED,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,KAAK,CACH,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,EACjD,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,EAC5D,cAAc,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,GACxC,IAAI,CAAC;IAER;;OAEG;IACH,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,MAAM,mBAAmB,GAAG,MAAM,UAAU,CAAC"}
|
|
@@ -26,6 +26,7 @@ export declare class CompositeDataSource implements DataSource {
|
|
|
26
26
|
private _initFactories;
|
|
27
27
|
private _syncFactories;
|
|
28
28
|
private _fdv1Synchronizers;
|
|
29
|
+
private _fdv1FallbackEngaged;
|
|
29
30
|
private _stopped;
|
|
30
31
|
private _externalTransitionPromise;
|
|
31
32
|
private _externalTransitionResolve?;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositeDataSource.d.ts","sourceRoot":"","sources":["../../src/datasource/CompositeDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EACL,UAAU,EACV,eAAe,EACf,mBAAmB,EACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AAOpD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1E;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;KAChC,CAAC,IAAI,eAAe,CAAC,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE;CACxE,CAAC;AAOF;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,UAAU;
|
|
1
|
+
{"version":3,"file":"CompositeDataSource.d.ts","sourceRoot":"","sources":["../../src/datasource/CompositeDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EACL,UAAU,EACV,eAAe,EACf,mBAAmB,EACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AAOpD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1E;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;KAChC,CAAC,IAAI,eAAe,CAAC,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE;CACxE,CAAC;AAOF;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,UAAU;IA8BlD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAUtC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAtC3B,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,kBAAkB,CAAsC;IAKhE,OAAO,CAAC,oBAAoB,CAAkB;IAE9C,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,0BAA0B,CAA6B;IAC/D,OAAO,CAAC,0BAA0B,CAAC,CAAqC;IACxE,OAAO,CAAC,aAAa,CAAsB;IAE3C;;;;;;;OAOG;gBAED,YAAY,EAAE,mBAAmB,EAAE,EACnC,aAAa,EAAE,mBAAmB,EAAE,EACpC,iBAAiB,EAAE,mBAAmB,EAAE,EACvB,OAAO,CAAC,sBAAU,EAClB,qBAAqB,GAAE,oBASvC,EACgB,QAAQ,GAAE,OAAyC;IAWhE,KAAK,CACT,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,EACjD,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,EAC5D,cAAc,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,GACxC,OAAO,CAAC,IAAI,CAAC;IAyMV,IAAI;IAMV,OAAO,CAAC,MAAM;IAad;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA0DvB;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAclC,OAAO,CAAC,iBAAiB,CAcvB;IAEF,OAAO,CAAC,mBAAmB;IAQ3B;;;;;;OAMG;IACH,OAAO,CAAC,gCAAgC;CAgCzC"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -985,11 +985,6 @@ class CallbackHandler {
|
|
|
985
985
|
}
|
|
986
986
|
|
|
987
987
|
// TODO: refactor client-sdk to use this enum
|
|
988
|
-
/**
|
|
989
|
-
* @experimental
|
|
990
|
-
* This feature is not stable and not subject to any backwards compatibility guarantees or semantic
|
|
991
|
-
* versioning. It is not suitable for production usage.
|
|
992
|
-
*/
|
|
993
988
|
var DataSourceState;
|
|
994
989
|
(function (DataSourceState) {
|
|
995
990
|
// Positive confirmation of connection/data receipt
|
|
@@ -1155,6 +1150,11 @@ class CompositeDataSource {
|
|
|
1155
1150
|
this._logger = _logger;
|
|
1156
1151
|
this._transitionConditions = _transitionConditions;
|
|
1157
1152
|
this._backoff = _backoff;
|
|
1153
|
+
// Set after the server-directed FDv1 fallback has been engaged. The directive is
|
|
1154
|
+
// one-way: subsequent fallback signals from the FDv1 synchronizer (e.g. if the FDv1
|
|
1155
|
+
// endpoint were to echo `x-ld-fd-fallback`) are ignored so the data source does not
|
|
1156
|
+
// loop replacing its synchronizer list with itself.
|
|
1157
|
+
this._fdv1FallbackEngaged = false;
|
|
1158
1158
|
this._stopped = true;
|
|
1159
1159
|
this._cancelTokens = [];
|
|
1160
1160
|
this._cancellableDelay = (delayMS) => {
|
|
@@ -1202,10 +1202,36 @@ class CompositeDataSource {
|
|
|
1202
1202
|
// secondary has been valid for N many seconds)
|
|
1203
1203
|
let lastState;
|
|
1204
1204
|
let cancelScheduledTransition = () => { };
|
|
1205
|
+
// Engages the FDv1 Fallback Directive: swaps the synchronizer list to FDv1 (or
|
|
1206
|
+
// empties it when no FDv1 fallback is configured), reports the in-progress status
|
|
1207
|
+
// through the sanitizer, cancels any pending scheduled transition, and resolves
|
|
1208
|
+
// a switchToSync transition. The directive is one-way; the engagement flag is
|
|
1209
|
+
// checked by the callers so we don't re-enter this branch on repeated signals.
|
|
1210
|
+
const engageFDv1Fallback = (statusToReport, err) => {
|
|
1211
|
+
if (this._fdv1Synchronizers.length() > 0) {
|
|
1212
|
+
this._logger?.warn(`Falling back to FDv1`);
|
|
1213
|
+
}
|
|
1214
|
+
else {
|
|
1215
|
+
this._logger?.warn(`FDv1 fallback was requested but no FDv1 fallback synchronizer is configured; data source will terminate`);
|
|
1216
|
+
}
|
|
1217
|
+
this._fdv1FallbackEngaged = true;
|
|
1218
|
+
this._syncFactories = this._fdv1Synchronizers;
|
|
1219
|
+
sanitizedStatusCallback(statusToReport, err);
|
|
1220
|
+
this._consumeCancelToken(cancelScheduledTransition);
|
|
1221
|
+
transitionResolve({ transition: 'switchToSync', err: err });
|
|
1222
|
+
};
|
|
1205
1223
|
// this callback handler can be disabled and ensures only one transition request occurs
|
|
1206
1224
|
const callbackHandler = new CallbackHandler((basis, data) => {
|
|
1207
1225
|
this._backoff.success();
|
|
1208
1226
|
dataCallback(basis, data);
|
|
1227
|
+
// The FDv1 fallback directive can ride along on the same data callback that
|
|
1228
|
+
// delivers a payload, so the swap to FDv1 is atomic with payload application.
|
|
1229
|
+
// Once engaged, the directive is one-way -- subsequent signals are ignored.
|
|
1230
|
+
if (data?.fallbackToFDv1 && !this._fdv1FallbackEngaged) {
|
|
1231
|
+
callbackHandler.disable();
|
|
1232
|
+
engageFDv1Fallback(DataSourceState.Interrupted, undefined);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1209
1235
|
if (basis && this._initPhaseActive) {
|
|
1210
1236
|
// transition to sync if we get basis during init
|
|
1211
1237
|
callbackHandler.disable();
|
|
@@ -1224,11 +1250,13 @@ class CompositeDataSource {
|
|
|
1224
1250
|
// don't use this datasource's factory again
|
|
1225
1251
|
this._logger?.debug(`Culling data source due to err ${err}`);
|
|
1226
1252
|
cullDSFactory?.();
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1253
|
+
}
|
|
1254
|
+
// Status-callback path for the FDv1 Fallback Directive (used when the
|
|
1255
|
+
// server-directed signal arrives without an accompanying payload, e.g. on
|
|
1256
|
+
// an HTTP error or a malformed body).
|
|
1257
|
+
if (err instanceof LDFlagDeliveryFallbackError && !this._fdv1FallbackEngaged) {
|
|
1258
|
+
engageFDv1Fallback(state, err);
|
|
1259
|
+
return;
|
|
1232
1260
|
}
|
|
1233
1261
|
sanitizedStatusCallback(state, err);
|
|
1234
1262
|
this._consumeCancelToken(cancelScheduledTransition);
|
|
@@ -1275,7 +1303,16 @@ class CompositeDataSource {
|
|
|
1275
1303
|
]);
|
|
1276
1304
|
// stop the underlying datasource before transitioning to next state
|
|
1277
1305
|
currentDS?.stop();
|
|
1278
|
-
|
|
1306
|
+
// Skip backoff only on the initial server-directed FDv1 engagement (a `switchToSync`
|
|
1307
|
+
// transition resolved by `engageFDv1Fallback` carries an `LDFlagDeliveryFallbackError`).
|
|
1308
|
+
// Any subsequent `LDFlagDeliveryFallbackError` is an ordinary retry from the FDv1
|
|
1309
|
+
// synchronizer (or a follow-up FDv1 factory) and must be throttled like any other
|
|
1310
|
+
// error retry.
|
|
1311
|
+
const isInitialFDv1Engagement = transitionRequest.transition === 'switchToSync' &&
|
|
1312
|
+
transitionRequest.err instanceof LDFlagDeliveryFallbackError;
|
|
1313
|
+
if (transitionRequest.err &&
|
|
1314
|
+
transitionRequest.transition !== 'stop' &&
|
|
1315
|
+
!isInitialFDv1Engagement) {
|
|
1279
1316
|
// if the transition was due to an error we're not in the initializer phase, throttle the transition. Fallback between initializers is not throttled.
|
|
1280
1317
|
const delay = this._initPhaseActive ? 0 : this._backoff.fail();
|
|
1281
1318
|
const { promise, cancel: cancelDelay } = this._cancellableDelay(delay);
|
|
@@ -1313,6 +1350,7 @@ class CompositeDataSource {
|
|
|
1313
1350
|
this._initFactories.reset();
|
|
1314
1351
|
this._syncFactories.reset();
|
|
1315
1352
|
this._fdv1Synchronizers.reset();
|
|
1353
|
+
this._fdv1FallbackEngaged = false;
|
|
1316
1354
|
this._externalTransitionPromise = new Promise((tr) => {
|
|
1317
1355
|
this._externalTransitionResolve = tr;
|
|
1318
1356
|
});
|
|
@@ -2197,7 +2235,7 @@ function fastDeepEqual(a, b) {
|
|
|
2197
2235
|
return a !== a && b !== b;
|
|
2198
2236
|
}
|
|
2199
2237
|
|
|
2200
|
-
function defaultHeaders(sdkKey, info, tags, includeAuthorizationHeader = true, userAgentHeaderName = 'user-agent') {
|
|
2238
|
+
function defaultHeaders(sdkKey, info, tags, includeAuthorizationHeader = true, userAgentHeaderName = 'user-agent', instanceId) {
|
|
2201
2239
|
const { userAgentBase, version, wrapperName, wrapperVersion } = info.sdkData();
|
|
2202
2240
|
const headers = {
|
|
2203
2241
|
[userAgentHeaderName]: `${userAgentBase ?? 'NodeJSClient'}/${version}`,
|
|
@@ -2215,6 +2253,14 @@ function defaultHeaders(sdkKey, info, tags, includeAuthorizationHeader = true, u
|
|
|
2215
2253
|
if (tags?.value) {
|
|
2216
2254
|
headers['x-launchdarkly-tags'] = tags.value;
|
|
2217
2255
|
}
|
|
2256
|
+
// Per SCMP-server-connection-minutes-polling (spec section 1.1), server SDKs include a
|
|
2257
|
+
// per-instance v4 GUID on every polling request. The caller (a server SDK) is responsible
|
|
2258
|
+
// for generating the GUID once per SDK instance and passing it here, so that it rides on
|
|
2259
|
+
// every outbound request via this shared default-headers map. Client/edge SDKs do not pass
|
|
2260
|
+
// this value, so the header is omitted for them.
|
|
2261
|
+
if (instanceId) {
|
|
2262
|
+
headers['x-launchdarkly-instance-id'] = instanceId;
|
|
2263
|
+
}
|
|
2218
2264
|
return headers;
|
|
2219
2265
|
}
|
|
2220
2266
|
function httpErrorMessage(err, context, retryMessage) {
|