@launchdarkly/js-client-sdk-common 1.17.2 → 1.18.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.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/DataManager.d.ts +2 -2
- package/dist/cjs/DataManager.d.ts.map +1 -1
- package/dist/cjs/LDEmitter.d.ts.map +1 -1
- package/dist/cjs/datasource/DataSourceEventHandler.d.ts +4 -6
- package/dist/cjs/datasource/DataSourceEventHandler.d.ts.map +1 -1
- package/dist/cjs/datasource/DataSourceStatus.d.ts +64 -14
- package/dist/cjs/datasource/DataSourceStatus.d.ts.map +1 -1
- package/dist/cjs/datasource/DataSourceStatusManager.d.ts +6 -17
- package/dist/cjs/datasource/DataSourceStatusManager.d.ts.map +1 -1
- package/dist/cjs/datasource/Requestor.d.ts +2 -9
- package/dist/cjs/datasource/Requestor.d.ts.map +1 -1
- package/dist/cjs/flag-manager/bootstrap.d.ts +6 -0
- package/dist/cjs/flag-manager/bootstrap.d.ts.map +1 -0
- package/dist/cjs/index.cjs +160 -150
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/streaming/StreamingProcessor.d.ts +1 -1
- package/dist/cjs/streaming/StreamingProcessor.d.ts.map +1 -1
- package/dist/esm/DataManager.d.ts +2 -2
- package/dist/esm/DataManager.d.ts.map +1 -1
- package/dist/esm/LDEmitter.d.ts.map +1 -1
- package/dist/esm/datasource/DataSourceEventHandler.d.ts +4 -6
- package/dist/esm/datasource/DataSourceEventHandler.d.ts.map +1 -1
- package/dist/esm/datasource/DataSourceStatus.d.ts +64 -14
- package/dist/esm/datasource/DataSourceStatus.d.ts.map +1 -1
- package/dist/esm/datasource/DataSourceStatusManager.d.ts +6 -17
- package/dist/esm/datasource/DataSourceStatusManager.d.ts.map +1 -1
- package/dist/esm/datasource/Requestor.d.ts +2 -9
- package/dist/esm/datasource/Requestor.d.ts.map +1 -1
- package/dist/esm/flag-manager/bootstrap.d.ts +6 -0
- package/dist/esm/flag-manager/bootstrap.d.ts.map +1 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +159 -150
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/streaming/StreamingProcessor.d.ts +1 -1
- package/dist/esm/streaming/StreamingProcessor.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -21,18 +21,17 @@ function _interopNamespaceDefault(e) {
|
|
|
21
21
|
|
|
22
22
|
var jsSdkCommon__namespace = /*#__PURE__*/_interopNamespaceDefault(jsSdkCommon);
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
24
|
+
// This is a temporary compat for react native. We should remove this once we
|
|
25
|
+
// major version react native SDK.
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
27
|
+
const DataSourceState = {
|
|
28
|
+
Initializing: 'INITIALIZING',
|
|
29
|
+
Valid: 'VALID',
|
|
30
|
+
Interrupted: 'INTERRUPTED',
|
|
31
|
+
SetOffline: 'SET_OFFLINE',
|
|
32
|
+
Closed: 'CLOSED',
|
|
33
|
+
};
|
|
34
34
|
|
|
35
|
-
// eslint-disable-next-line max-classes-per-file
|
|
36
35
|
function isOk(status) {
|
|
37
36
|
return status >= 200 && status <= 299;
|
|
38
37
|
}
|
|
@@ -43,38 +42,6 @@ class LDRequestError extends Error {
|
|
|
43
42
|
this.name = 'LaunchDarklyRequestError';
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Note: The requestor is implemented independently from polling such that it can be used to
|
|
48
|
-
* make a one-off request.
|
|
49
|
-
*/
|
|
50
|
-
class Requestor {
|
|
51
|
-
constructor(_requests, _uri, _headers, _method, _body) {
|
|
52
|
-
this._requests = _requests;
|
|
53
|
-
this._uri = _uri;
|
|
54
|
-
this._headers = _headers;
|
|
55
|
-
this._method = _method;
|
|
56
|
-
this._body = _body;
|
|
57
|
-
}
|
|
58
|
-
async requestPayload() {
|
|
59
|
-
let status;
|
|
60
|
-
try {
|
|
61
|
-
const res = await this._requests.fetch(this._uri, {
|
|
62
|
-
method: this._method,
|
|
63
|
-
headers: this._headers,
|
|
64
|
-
body: this._body,
|
|
65
|
-
});
|
|
66
|
-
if (isOk(res.status)) {
|
|
67
|
-
return await res.text();
|
|
68
|
-
}
|
|
69
|
-
// Assigning so it can be thrown after the try/catch.
|
|
70
|
-
status = res.status;
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
throw new LDRequestError(err?.message);
|
|
74
|
-
}
|
|
75
|
-
throw new LDRequestError(`Unexpected status code: ${status}`, status);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
45
|
function makeRequestor(plainContextString, serviceEndpoints, paths, requests, encoding, baseHeaders, baseQueryParams, withReasons, useReport, secureModeHash) {
|
|
79
46
|
let body;
|
|
80
47
|
let method = 'GET';
|
|
@@ -95,7 +62,27 @@ function makeRequestor(plainContextString, serviceEndpoints, paths, requests, en
|
|
|
95
62
|
parameters.push({ key: 'h', value: secureModeHash });
|
|
96
63
|
}
|
|
97
64
|
const uri = jsSdkCommon.getPollingUri(serviceEndpoints, path, parameters);
|
|
98
|
-
return
|
|
65
|
+
return {
|
|
66
|
+
async requestPayload() {
|
|
67
|
+
let status;
|
|
68
|
+
try {
|
|
69
|
+
const res = await requests.fetch(uri, {
|
|
70
|
+
method,
|
|
71
|
+
headers,
|
|
72
|
+
body,
|
|
73
|
+
});
|
|
74
|
+
if (isOk(res.status)) {
|
|
75
|
+
return await res.text();
|
|
76
|
+
}
|
|
77
|
+
// Assigning so it can be thrown after the try/catch.
|
|
78
|
+
status = res.status;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
throw new LDRequestError(err?.message);
|
|
82
|
+
}
|
|
83
|
+
throw new LDRequestError(`Unexpected status code: ${status}`, status);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
99
86
|
}
|
|
100
87
|
|
|
101
88
|
const duplicateExecutionError = new Error('Task has already been executed or shed. This is likely an implementation error. The task will not be executed again.');
|
|
@@ -1339,6 +1326,10 @@ class LDEmitter {
|
|
|
1339
1326
|
this._listeners = new Map();
|
|
1340
1327
|
}
|
|
1341
1328
|
on(name, listener) {
|
|
1329
|
+
if (typeof name !== 'string') {
|
|
1330
|
+
this._logger?.warn('Only string event names are supported.');
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1342
1333
|
if (!this._listeners.has(name)) {
|
|
1343
1334
|
this._listeners.set(name, [listener]);
|
|
1344
1335
|
}
|
|
@@ -1949,117 +1940,135 @@ function safeRegisterDebugOverridePlugins(logger, debugOverride, plugins) {
|
|
|
1949
1940
|
});
|
|
1950
1941
|
}
|
|
1951
1942
|
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
}
|
|
1991
|
-
handleStreamingError(error) {
|
|
1992
|
-
this._statusManager.reportError(error.kind, error.message, error.code, error.recoverable);
|
|
1993
|
-
}
|
|
1994
|
-
handlePollingError(error) {
|
|
1995
|
-
this._statusManager.reportError(error.kind, error.message, error.status, error.recoverable);
|
|
1996
|
-
}
|
|
1943
|
+
function readFlagsFromBootstrap(logger, data) {
|
|
1944
|
+
// If the bootstrap data came from an older server-side SDK, we'll have just a map of keys to values.
|
|
1945
|
+
// Newer SDKs that have an allFlagsState method will provide an extra "$flagsState" key that contains
|
|
1946
|
+
// the rest of the metadata we want. We do it this way for backward compatibility with older JS SDKs.
|
|
1947
|
+
const keys = Object.keys(data);
|
|
1948
|
+
const metadataKey = '$flagsState';
|
|
1949
|
+
const validKey = '$valid';
|
|
1950
|
+
const metadata = data[metadataKey];
|
|
1951
|
+
if (!metadata && keys.length) {
|
|
1952
|
+
logger.warn('LaunchDarkly client was initialized with bootstrap data that did not include flag' +
|
|
1953
|
+
' metadata. Events may not be sent correctly.');
|
|
1954
|
+
}
|
|
1955
|
+
if (data[validKey] === false) {
|
|
1956
|
+
logger.warn('LaunchDarkly bootstrap data is not available because the back end could not read the flags.');
|
|
1957
|
+
}
|
|
1958
|
+
const ret = {};
|
|
1959
|
+
keys.forEach((key) => {
|
|
1960
|
+
if (key !== metadataKey && key !== validKey) {
|
|
1961
|
+
let flag;
|
|
1962
|
+
if (metadata && metadata[key]) {
|
|
1963
|
+
flag = {
|
|
1964
|
+
value: data[key],
|
|
1965
|
+
...metadata[key],
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1968
|
+
else {
|
|
1969
|
+
flag = {
|
|
1970
|
+
value: data[key],
|
|
1971
|
+
version: 0,
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
ret[key] = {
|
|
1975
|
+
version: flag.version,
|
|
1976
|
+
flag,
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1979
|
+
});
|
|
1980
|
+
return ret;
|
|
1997
1981
|
}
|
|
1998
1982
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
1983
|
+
function createDataSourceEventHandler(flagManager, statusManager, logger) {
|
|
1984
|
+
return {
|
|
1985
|
+
async handlePut(context, flags) {
|
|
1986
|
+
logger.debug(`Got PUT: ${Object.keys(flags)}`);
|
|
1987
|
+
// mapping flags to item descriptors
|
|
1988
|
+
const descriptors = Object.entries(flags).reduce((acc, [key, flag]) => {
|
|
1989
|
+
acc[key] = { version: flag.version, flag };
|
|
1990
|
+
return acc;
|
|
1991
|
+
}, {});
|
|
1992
|
+
await flagManager.init(context, descriptors);
|
|
1993
|
+
statusManager.requestStateUpdate('VALID');
|
|
1994
|
+
},
|
|
1995
|
+
async handlePatch(context, patchFlag) {
|
|
1996
|
+
logger.debug(`Got PATCH ${JSON.stringify(patchFlag, null, 2)}`);
|
|
1997
|
+
flagManager.upsert(context, patchFlag.key, {
|
|
1998
|
+
version: patchFlag.version,
|
|
1999
|
+
flag: patchFlag,
|
|
2000
|
+
});
|
|
2001
|
+
},
|
|
2002
|
+
async handleDelete(context, deleteFlag) {
|
|
2003
|
+
logger.debug(`Got DELETE ${JSON.stringify(deleteFlag, null, 2)}`);
|
|
2004
|
+
flagManager.upsert(context, deleteFlag.key, {
|
|
2005
|
+
version: deleteFlag.version,
|
|
2006
|
+
flag: {
|
|
2007
|
+
...deleteFlag,
|
|
2008
|
+
deleted: true,
|
|
2009
|
+
// props below are set to sensible defaults. they are irrelevant
|
|
2010
|
+
// because this flag has been deleted.
|
|
2011
|
+
flagVersion: 0,
|
|
2012
|
+
value: undefined,
|
|
2013
|
+
variation: 0,
|
|
2014
|
+
trackEvents: false,
|
|
2015
|
+
},
|
|
2016
|
+
});
|
|
2017
|
+
},
|
|
2018
|
+
handleStreamingError(error) {
|
|
2019
|
+
statusManager.reportError(error.kind, error.message, error.code, error.recoverable);
|
|
2020
|
+
},
|
|
2021
|
+
handlePollingError(error) {
|
|
2022
|
+
statusManager.reportError(error.kind, error.message, error.status, error.recoverable);
|
|
2023
|
+
},
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
function createDataSourceStatusManager(emitter, timeStamper = () => Date.now()) {
|
|
2028
|
+
let state = 'CLOSED';
|
|
2029
|
+
let stateSinceMillis = timeStamper();
|
|
2030
|
+
let errorInfo;
|
|
2031
|
+
function getStatus() {
|
|
2010
2032
|
return {
|
|
2011
|
-
state
|
|
2012
|
-
stateSince:
|
|
2013
|
-
lastError:
|
|
2033
|
+
state,
|
|
2034
|
+
stateSince: stateSinceMillis,
|
|
2035
|
+
lastError: errorInfo,
|
|
2014
2036
|
};
|
|
2015
2037
|
}
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
* @param requestedState to track
|
|
2020
|
-
* @param isError to indicate that the state update is a result of an error occurring.
|
|
2021
|
-
*/
|
|
2022
|
-
_updateState(requestedState, isError = false) {
|
|
2023
|
-
const newState = requestedState === exports.DataSourceState.Interrupted && this._state === exports.DataSourceState.Initializing // don't go to interrupted from initializing (recoverable errors when initializing are not noteworthy)
|
|
2024
|
-
? exports.DataSourceState.Initializing
|
|
2038
|
+
function updateState(requestedState, isError = false) {
|
|
2039
|
+
const newState = requestedState === 'INTERRUPTED' && state === 'INITIALIZING' // don't go to interrupted from initializing (recoverable errors when initializing are not noteworthy)
|
|
2040
|
+
? 'INITIALIZING'
|
|
2025
2041
|
: requestedState;
|
|
2026
|
-
const changedState =
|
|
2042
|
+
const changedState = state !== newState;
|
|
2027
2043
|
if (changedState) {
|
|
2028
|
-
|
|
2029
|
-
|
|
2044
|
+
state = newState;
|
|
2045
|
+
stateSinceMillis = timeStamper();
|
|
2030
2046
|
}
|
|
2031
2047
|
if (changedState || isError) {
|
|
2032
|
-
|
|
2048
|
+
emitter.emit('dataSourceStatus', getStatus());
|
|
2033
2049
|
}
|
|
2034
2050
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
message,
|
|
2057
|
-
statusCode,
|
|
2058
|
-
time: this._timeStamper(),
|
|
2059
|
-
};
|
|
2060
|
-
this._errorInfo = errorInfo;
|
|
2061
|
-
this._updateState(recoverable ? exports.DataSourceState.Interrupted : exports.DataSourceState.Closed, true);
|
|
2062
|
-
}
|
|
2051
|
+
return {
|
|
2052
|
+
get status() {
|
|
2053
|
+
return getStatus();
|
|
2054
|
+
},
|
|
2055
|
+
requestStateUpdate(requestedState) {
|
|
2056
|
+
updateState(requestedState);
|
|
2057
|
+
},
|
|
2058
|
+
reportError(kind, message, statusCode, recoverable = false) {
|
|
2059
|
+
errorInfo = {
|
|
2060
|
+
kind,
|
|
2061
|
+
message,
|
|
2062
|
+
statusCode,
|
|
2063
|
+
time: timeStamper(),
|
|
2064
|
+
};
|
|
2065
|
+
updateState(recoverable ? 'INTERRUPTED' : 'CLOSED', true);
|
|
2066
|
+
},
|
|
2067
|
+
// TODO: SDK-702 - Implement network availability behaviors
|
|
2068
|
+
// setNetworkUnavailable() {
|
|
2069
|
+
// updateState(DataSourceState.NetworkUnavailable);
|
|
2070
|
+
// },
|
|
2071
|
+
};
|
|
2063
2072
|
}
|
|
2064
2073
|
|
|
2065
2074
|
function reportClosed(logger) {
|
|
@@ -2341,8 +2350,8 @@ class BaseDataManager {
|
|
|
2341
2350
|
this.diagnosticsManager = diagnosticsManager;
|
|
2342
2351
|
this.closed = false;
|
|
2343
2352
|
this.logger = config.logger;
|
|
2344
|
-
this.dataSourceStatusManager =
|
|
2345
|
-
this._dataSourceEventHandler =
|
|
2353
|
+
this.dataSourceStatusManager = createDataSourceStatusManager(emitter);
|
|
2354
|
+
this._dataSourceEventHandler = createDataSourceEventHandler(flagManager, this.dataSourceStatusManager, this.config.logger);
|
|
2346
2355
|
}
|
|
2347
2356
|
/**
|
|
2348
2357
|
* Set additional connection parameters for requests polling/streaming.
|
|
@@ -2405,16 +2414,16 @@ class BaseDataManager {
|
|
|
2405
2414
|
return {
|
|
2406
2415
|
start: () => {
|
|
2407
2416
|
// update status before starting processor to ensure potential errors are reported after initializing
|
|
2408
|
-
statusManager.requestStateUpdate(
|
|
2417
|
+
statusManager.requestStateUpdate('INITIALIZING');
|
|
2409
2418
|
processor.start();
|
|
2410
2419
|
},
|
|
2411
2420
|
stop: () => {
|
|
2412
2421
|
processor.stop();
|
|
2413
|
-
statusManager.requestStateUpdate(
|
|
2422
|
+
statusManager.requestStateUpdate('CLOSED');
|
|
2414
2423
|
},
|
|
2415
2424
|
close: () => {
|
|
2416
2425
|
processor.close();
|
|
2417
|
-
statusManager.requestStateUpdate(
|
|
2426
|
+
statusManager.requestStateUpdate('CLOSED');
|
|
2418
2427
|
},
|
|
2419
2428
|
};
|
|
2420
2429
|
}
|
|
@@ -2426,9 +2435,10 @@ class BaseDataManager {
|
|
|
2426
2435
|
|
|
2427
2436
|
exports.platform = jsSdkCommon__namespace;
|
|
2428
2437
|
exports.BaseDataManager = BaseDataManager;
|
|
2438
|
+
exports.DataSourceState = DataSourceState;
|
|
2429
2439
|
exports.LDClientImpl = LDClientImpl;
|
|
2430
|
-
exports.Requestor = Requestor;
|
|
2431
2440
|
exports.makeRequestor = makeRequestor;
|
|
2441
|
+
exports.readFlagsFromBootstrap = readFlagsFromBootstrap;
|
|
2432
2442
|
exports.safeRegisterDebugOverridePlugins = safeRegisterDebugOverridePlugins;
|
|
2433
2443
|
Object.keys(jsSdkCommon).forEach(function (k) {
|
|
2434
2444
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|