@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.
Files changed (40) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/DataManager.d.ts +2 -2
  3. package/dist/cjs/DataManager.d.ts.map +1 -1
  4. package/dist/cjs/LDEmitter.d.ts.map +1 -1
  5. package/dist/cjs/datasource/DataSourceEventHandler.d.ts +4 -6
  6. package/dist/cjs/datasource/DataSourceEventHandler.d.ts.map +1 -1
  7. package/dist/cjs/datasource/DataSourceStatus.d.ts +64 -14
  8. package/dist/cjs/datasource/DataSourceStatus.d.ts.map +1 -1
  9. package/dist/cjs/datasource/DataSourceStatusManager.d.ts +6 -17
  10. package/dist/cjs/datasource/DataSourceStatusManager.d.ts.map +1 -1
  11. package/dist/cjs/datasource/Requestor.d.ts +2 -9
  12. package/dist/cjs/datasource/Requestor.d.ts.map +1 -1
  13. package/dist/cjs/flag-manager/bootstrap.d.ts +6 -0
  14. package/dist/cjs/flag-manager/bootstrap.d.ts.map +1 -0
  15. package/dist/cjs/index.cjs +160 -150
  16. package/dist/cjs/index.cjs.map +1 -1
  17. package/dist/cjs/index.d.ts +2 -1
  18. package/dist/cjs/index.d.ts.map +1 -1
  19. package/dist/cjs/streaming/StreamingProcessor.d.ts +1 -1
  20. package/dist/cjs/streaming/StreamingProcessor.d.ts.map +1 -1
  21. package/dist/esm/DataManager.d.ts +2 -2
  22. package/dist/esm/DataManager.d.ts.map +1 -1
  23. package/dist/esm/LDEmitter.d.ts.map +1 -1
  24. package/dist/esm/datasource/DataSourceEventHandler.d.ts +4 -6
  25. package/dist/esm/datasource/DataSourceEventHandler.d.ts.map +1 -1
  26. package/dist/esm/datasource/DataSourceStatus.d.ts +64 -14
  27. package/dist/esm/datasource/DataSourceStatus.d.ts.map +1 -1
  28. package/dist/esm/datasource/DataSourceStatusManager.d.ts +6 -17
  29. package/dist/esm/datasource/DataSourceStatusManager.d.ts.map +1 -1
  30. package/dist/esm/datasource/Requestor.d.ts +2 -9
  31. package/dist/esm/datasource/Requestor.d.ts.map +1 -1
  32. package/dist/esm/flag-manager/bootstrap.d.ts +6 -0
  33. package/dist/esm/flag-manager/bootstrap.d.ts.map +1 -0
  34. package/dist/esm/index.d.ts +2 -1
  35. package/dist/esm/index.d.ts.map +1 -1
  36. package/dist/esm/index.mjs +159 -150
  37. package/dist/esm/index.mjs.map +1 -1
  38. package/dist/esm/streaming/StreamingProcessor.d.ts +1 -1
  39. package/dist/esm/streaming/StreamingProcessor.d.ts.map +1 -1
  40. package/package.json +1 -1
@@ -21,18 +21,17 @@ function _interopNamespaceDefault(e) {
21
21
 
22
22
  var jsSdkCommon__namespace = /*#__PURE__*/_interopNamespaceDefault(jsSdkCommon);
23
23
 
24
- exports.DataSourceState = void 0;
25
- (function (DataSourceState) {
26
- DataSourceState["Initializing"] = "INITIALIZING";
27
- DataSourceState["Valid"] = "VALID";
28
- DataSourceState["Interrupted"] = "INTERRUPTED";
29
- DataSourceState["SetOffline"] = "SET_OFFLINE";
30
- DataSourceState["Closed"] = "CLOSED";
31
- // TODO: SDK-702 - Implement network availability behaviors
32
- // NetworkUnavailable,
33
- })(exports.DataSourceState || (exports.DataSourceState = {}));
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 new Requestor(requests, uri, headers, method, body);
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
- class DataSourceEventHandler {
1953
- constructor(_flagManager, _statusManager, _logger) {
1954
- this._flagManager = _flagManager;
1955
- this._statusManager = _statusManager;
1956
- this._logger = _logger;
1957
- }
1958
- async handlePut(context, flags) {
1959
- this._logger.debug(`Got PUT: ${Object.keys(flags)}`);
1960
- // mapping flags to item descriptors
1961
- const descriptors = Object.entries(flags).reduce((acc, [key, flag]) => {
1962
- acc[key] = { version: flag.version, flag };
1963
- return acc;
1964
- }, {});
1965
- await this._flagManager.init(context, descriptors);
1966
- this._statusManager.requestStateUpdate(exports.DataSourceState.Valid);
1967
- }
1968
- async handlePatch(context, patchFlag) {
1969
- this._logger.debug(`Got PATCH ${JSON.stringify(patchFlag, null, 2)}`);
1970
- this._flagManager.upsert(context, patchFlag.key, {
1971
- version: patchFlag.version,
1972
- flag: patchFlag,
1973
- });
1974
- }
1975
- async handleDelete(context, deleteFlag) {
1976
- this._logger.debug(`Got DELETE ${JSON.stringify(deleteFlag, null, 2)}`);
1977
- this._flagManager.upsert(context, deleteFlag.key, {
1978
- version: deleteFlag.version,
1979
- flag: {
1980
- ...deleteFlag,
1981
- deleted: true,
1982
- // props below are set to sensible defaults. they are irrelevant
1983
- // because this flag has been deleted.
1984
- flagVersion: 0,
1985
- value: undefined,
1986
- variation: 0,
1987
- trackEvents: false,
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
- * Tracks the current data source status and emits updates when the status changes.
2001
- */
2002
- class DataSourceStatusManager {
2003
- constructor(_emitter, timeStamper = () => Date.now()) {
2004
- this._emitter = _emitter;
2005
- this._state = exports.DataSourceState.Closed;
2006
- this._stateSinceMillis = timeStamper();
2007
- this._timeStamper = timeStamper;
2008
- }
2009
- get status() {
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: this._state,
2012
- stateSince: this._stateSinceMillis,
2013
- lastError: this._errorInfo,
2033
+ state,
2034
+ stateSince: stateSinceMillis,
2035
+ lastError: errorInfo,
2014
2036
  };
2015
2037
  }
2016
- /**
2017
- * Updates the state of the manager.
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 = this._state !== newState;
2042
+ const changedState = state !== newState;
2027
2043
  if (changedState) {
2028
- this._state = newState;
2029
- this._stateSinceMillis = this._timeStamper();
2044
+ state = newState;
2045
+ stateSinceMillis = timeStamper();
2030
2046
  }
2031
2047
  if (changedState || isError) {
2032
- this._emitter.emit('dataSourceStatus', this.status);
2048
+ emitter.emit('dataSourceStatus', getStatus());
2033
2049
  }
2034
2050
  }
2035
- /**
2036
- * Requests the manager move to the provided state. This request may be ignored
2037
- * if the current state cannot transition to the requested state.
2038
- * @param state that is requested
2039
- */
2040
- requestStateUpdate(state) {
2041
- this._updateState(state);
2042
- }
2043
- /**
2044
- * Reports a datasource error to this manager. Since the {@link DataSourceStatus} includes error
2045
- * information, it is possible that that a {@link DataSourceStatus} update is emitted with
2046
- * the same {@link DataSourceState}.
2047
- *
2048
- * @param kind of the error
2049
- * @param message for the error
2050
- * @param statusCode of the error if there was one
2051
- * @param recoverable to indicate that the error is anticipated to be recoverable
2052
- */
2053
- reportError(kind, message, statusCode, recoverable = false) {
2054
- const errorInfo = {
2055
- kind,
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 = new DataSourceStatusManager(emitter);
2345
- this._dataSourceEventHandler = new DataSourceEventHandler(flagManager, this.dataSourceStatusManager, this.config.logger);
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(exports.DataSourceState.Initializing);
2417
+ statusManager.requestStateUpdate('INITIALIZING');
2409
2418
  processor.start();
2410
2419
  },
2411
2420
  stop: () => {
2412
2421
  processor.stop();
2413
- statusManager.requestStateUpdate(exports.DataSourceState.Closed);
2422
+ statusManager.requestStateUpdate('CLOSED');
2414
2423
  },
2415
2424
  close: () => {
2416
2425
  processor.close();
2417
- statusManager.requestStateUpdate(exports.DataSourceState.Closed);
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, {