@launchdarkly/js-client-sdk-common 1.17.1 → 1.18.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/DataManager.d.ts +2 -2
  3. package/dist/cjs/DataManager.d.ts.map +1 -1
  4. package/dist/cjs/LDClientImpl.d.ts +3 -3
  5. package/dist/cjs/LDClientImpl.d.ts.map +1 -1
  6. package/dist/cjs/api/LDClient.d.ts +3 -2
  7. package/dist/cjs/api/LDClient.d.ts.map +1 -1
  8. package/dist/cjs/api/LDContext.d.ts +64 -0
  9. package/dist/cjs/api/LDContext.d.ts.map +1 -0
  10. package/dist/cjs/api/LDEvaluationDetail.d.ts +2 -2
  11. package/dist/cjs/api/LDEvaluationDetail.d.ts.map +1 -1
  12. package/dist/cjs/api/index.d.ts +1 -0
  13. package/dist/cjs/api/index.d.ts.map +1 -1
  14. package/dist/cjs/context/ensureKey.d.ts +3 -2
  15. package/dist/cjs/context/ensureKey.d.ts.map +1 -1
  16. package/dist/cjs/datasource/DataSourceEventHandler.d.ts +4 -6
  17. package/dist/cjs/datasource/DataSourceEventHandler.d.ts.map +1 -1
  18. package/dist/cjs/datasource/DataSourceStatus.d.ts +64 -14
  19. package/dist/cjs/datasource/DataSourceStatus.d.ts.map +1 -1
  20. package/dist/cjs/datasource/DataSourceStatusManager.d.ts +6 -17
  21. package/dist/cjs/datasource/DataSourceStatusManager.d.ts.map +1 -1
  22. package/dist/cjs/datasource/Requestor.d.ts +2 -9
  23. package/dist/cjs/datasource/Requestor.d.ts.map +1 -1
  24. package/dist/cjs/flag-manager/bootstrap.d.ts +6 -0
  25. package/dist/cjs/flag-manager/bootstrap.d.ts.map +1 -0
  26. package/dist/cjs/index.cjs +157 -154
  27. package/dist/cjs/index.cjs.map +1 -1
  28. package/dist/cjs/index.d.ts +3 -2
  29. package/dist/cjs/index.d.ts.map +1 -1
  30. package/dist/cjs/streaming/StreamingProcessor.d.ts +1 -1
  31. package/dist/cjs/streaming/StreamingProcessor.d.ts.map +1 -1
  32. package/dist/esm/DataManager.d.ts +2 -2
  33. package/dist/esm/DataManager.d.ts.map +1 -1
  34. package/dist/esm/LDClientImpl.d.ts +3 -3
  35. package/dist/esm/LDClientImpl.d.ts.map +1 -1
  36. package/dist/esm/api/LDClient.d.ts +3 -2
  37. package/dist/esm/api/LDClient.d.ts.map +1 -1
  38. package/dist/esm/api/LDContext.d.ts +64 -0
  39. package/dist/esm/api/LDContext.d.ts.map +1 -0
  40. package/dist/esm/api/LDEvaluationDetail.d.ts +2 -2
  41. package/dist/esm/api/LDEvaluationDetail.d.ts.map +1 -1
  42. package/dist/esm/api/index.d.ts +1 -0
  43. package/dist/esm/api/index.d.ts.map +1 -1
  44. package/dist/esm/context/ensureKey.d.ts +3 -2
  45. package/dist/esm/context/ensureKey.d.ts.map +1 -1
  46. package/dist/esm/datasource/DataSourceEventHandler.d.ts +4 -6
  47. package/dist/esm/datasource/DataSourceEventHandler.d.ts.map +1 -1
  48. package/dist/esm/datasource/DataSourceStatus.d.ts +64 -14
  49. package/dist/esm/datasource/DataSourceStatus.d.ts.map +1 -1
  50. package/dist/esm/datasource/DataSourceStatusManager.d.ts +6 -17
  51. package/dist/esm/datasource/DataSourceStatusManager.d.ts.map +1 -1
  52. package/dist/esm/datasource/Requestor.d.ts +2 -9
  53. package/dist/esm/datasource/Requestor.d.ts.map +1 -1
  54. package/dist/esm/flag-manager/bootstrap.d.ts +6 -0
  55. package/dist/esm/flag-manager/bootstrap.d.ts.map +1 -0
  56. package/dist/esm/index.d.ts +3 -2
  57. package/dist/esm/index.d.ts.map +1 -1
  58. package/dist/esm/index.mjs +156 -154
  59. package/dist/esm/index.mjs.map +1 -1
  60. package/dist/esm/streaming/StreamingProcessor.d.ts +1 -1
  61. package/dist/esm/streaming/StreamingProcessor.d.ts.map +1 -1
  62. 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.');
@@ -657,7 +644,7 @@ function createSuccessEvaluationDetail(value, variationIndex, reason) {
657
644
  const res = {
658
645
  value,
659
646
  variationIndex: variationIndex ?? null,
660
- reason: reason ?? null,
647
+ ...(reason !== undefined && { reason }),
661
648
  };
662
649
  return res;
663
650
  }
@@ -1913,9 +1900,6 @@ class LDClientImpl {
1913
1900
  else {
1914
1901
  details[flagKey] = {
1915
1902
  value: undefined,
1916
- // For backwards compatibility purposes reason and variationIndex are null instead of
1917
- // being undefined.
1918
- reason: null,
1919
1903
  variationIndex: null,
1920
1904
  };
1921
1905
  }
@@ -1952,117 +1936,135 @@ function safeRegisterDebugOverridePlugins(logger, debugOverride, plugins) {
1952
1936
  });
1953
1937
  }
1954
1938
 
1955
- class DataSourceEventHandler {
1956
- constructor(_flagManager, _statusManager, _logger) {
1957
- this._flagManager = _flagManager;
1958
- this._statusManager = _statusManager;
1959
- this._logger = _logger;
1960
- }
1961
- async handlePut(context, flags) {
1962
- this._logger.debug(`Got PUT: ${Object.keys(flags)}`);
1963
- // mapping flags to item descriptors
1964
- const descriptors = Object.entries(flags).reduce((acc, [key, flag]) => {
1965
- acc[key] = { version: flag.version, flag };
1966
- return acc;
1967
- }, {});
1968
- await this._flagManager.init(context, descriptors);
1969
- this._statusManager.requestStateUpdate(exports.DataSourceState.Valid);
1970
- }
1971
- async handlePatch(context, patchFlag) {
1972
- this._logger.debug(`Got PATCH ${JSON.stringify(patchFlag, null, 2)}`);
1973
- this._flagManager.upsert(context, patchFlag.key, {
1974
- version: patchFlag.version,
1975
- flag: patchFlag,
1976
- });
1977
- }
1978
- async handleDelete(context, deleteFlag) {
1979
- this._logger.debug(`Got DELETE ${JSON.stringify(deleteFlag, null, 2)}`);
1980
- this._flagManager.upsert(context, deleteFlag.key, {
1981
- version: deleteFlag.version,
1982
- flag: {
1983
- ...deleteFlag,
1984
- deleted: true,
1985
- // props below are set to sensible defaults. they are irrelevant
1986
- // because this flag has been deleted.
1987
- flagVersion: 0,
1988
- value: undefined,
1989
- variation: 0,
1990
- trackEvents: false,
1991
- },
1992
- });
1993
- }
1994
- handleStreamingError(error) {
1995
- this._statusManager.reportError(error.kind, error.message, error.code, error.recoverable);
1996
- }
1997
- handlePollingError(error) {
1998
- this._statusManager.reportError(error.kind, error.message, error.status, error.recoverable);
1999
- }
1939
+ function readFlagsFromBootstrap(logger, data) {
1940
+ // If the bootstrap data came from an older server-side SDK, we'll have just a map of keys to values.
1941
+ // Newer SDKs that have an allFlagsState method will provide an extra "$flagsState" key that contains
1942
+ // the rest of the metadata we want. We do it this way for backward compatibility with older JS SDKs.
1943
+ const keys = Object.keys(data);
1944
+ const metadataKey = '$flagsState';
1945
+ const validKey = '$valid';
1946
+ const metadata = data[metadataKey];
1947
+ if (!metadata && keys.length) {
1948
+ logger.warn('LaunchDarkly client was initialized with bootstrap data that did not include flag' +
1949
+ ' metadata. Events may not be sent correctly.');
1950
+ }
1951
+ if (data[validKey] === false) {
1952
+ logger.warn('LaunchDarkly bootstrap data is not available because the back end could not read the flags.');
1953
+ }
1954
+ const ret = {};
1955
+ keys.forEach((key) => {
1956
+ if (key !== metadataKey && key !== validKey) {
1957
+ let flag;
1958
+ if (metadata && metadata[key]) {
1959
+ flag = {
1960
+ value: data[key],
1961
+ ...metadata[key],
1962
+ };
1963
+ }
1964
+ else {
1965
+ flag = {
1966
+ value: data[key],
1967
+ version: 0,
1968
+ };
1969
+ }
1970
+ ret[key] = {
1971
+ version: flag.version,
1972
+ flag,
1973
+ };
1974
+ }
1975
+ });
1976
+ return ret;
2000
1977
  }
2001
1978
 
2002
- /**
2003
- * Tracks the current data source status and emits updates when the status changes.
2004
- */
2005
- class DataSourceStatusManager {
2006
- constructor(_emitter, timeStamper = () => Date.now()) {
2007
- this._emitter = _emitter;
2008
- this._state = exports.DataSourceState.Closed;
2009
- this._stateSinceMillis = timeStamper();
2010
- this._timeStamper = timeStamper;
2011
- }
2012
- get status() {
1979
+ function createDataSourceEventHandler(flagManager, statusManager, logger) {
1980
+ return {
1981
+ async handlePut(context, flags) {
1982
+ logger.debug(`Got PUT: ${Object.keys(flags)}`);
1983
+ // mapping flags to item descriptors
1984
+ const descriptors = Object.entries(flags).reduce((acc, [key, flag]) => {
1985
+ acc[key] = { version: flag.version, flag };
1986
+ return acc;
1987
+ }, {});
1988
+ await flagManager.init(context, descriptors);
1989
+ statusManager.requestStateUpdate('VALID');
1990
+ },
1991
+ async handlePatch(context, patchFlag) {
1992
+ logger.debug(`Got PATCH ${JSON.stringify(patchFlag, null, 2)}`);
1993
+ flagManager.upsert(context, patchFlag.key, {
1994
+ version: patchFlag.version,
1995
+ flag: patchFlag,
1996
+ });
1997
+ },
1998
+ async handleDelete(context, deleteFlag) {
1999
+ logger.debug(`Got DELETE ${JSON.stringify(deleteFlag, null, 2)}`);
2000
+ flagManager.upsert(context, deleteFlag.key, {
2001
+ version: deleteFlag.version,
2002
+ flag: {
2003
+ ...deleteFlag,
2004
+ deleted: true,
2005
+ // props below are set to sensible defaults. they are irrelevant
2006
+ // because this flag has been deleted.
2007
+ flagVersion: 0,
2008
+ value: undefined,
2009
+ variation: 0,
2010
+ trackEvents: false,
2011
+ },
2012
+ });
2013
+ },
2014
+ handleStreamingError(error) {
2015
+ statusManager.reportError(error.kind, error.message, error.code, error.recoverable);
2016
+ },
2017
+ handlePollingError(error) {
2018
+ statusManager.reportError(error.kind, error.message, error.status, error.recoverable);
2019
+ },
2020
+ };
2021
+ }
2022
+
2023
+ function createDataSourceStatusManager(emitter, timeStamper = () => Date.now()) {
2024
+ let state = 'CLOSED';
2025
+ let stateSinceMillis = timeStamper();
2026
+ let errorInfo;
2027
+ function getStatus() {
2013
2028
  return {
2014
- state: this._state,
2015
- stateSince: this._stateSinceMillis,
2016
- lastError: this._errorInfo,
2029
+ state,
2030
+ stateSince: stateSinceMillis,
2031
+ lastError: errorInfo,
2017
2032
  };
2018
2033
  }
2019
- /**
2020
- * Updates the state of the manager.
2021
- *
2022
- * @param requestedState to track
2023
- * @param isError to indicate that the state update is a result of an error occurring.
2024
- */
2025
- _updateState(requestedState, isError = false) {
2026
- 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)
2027
- ? exports.DataSourceState.Initializing
2034
+ function updateState(requestedState, isError = false) {
2035
+ const newState = requestedState === 'INTERRUPTED' && state === 'INITIALIZING' // don't go to interrupted from initializing (recoverable errors when initializing are not noteworthy)
2036
+ ? 'INITIALIZING'
2028
2037
  : requestedState;
2029
- const changedState = this._state !== newState;
2038
+ const changedState = state !== newState;
2030
2039
  if (changedState) {
2031
- this._state = newState;
2032
- this._stateSinceMillis = this._timeStamper();
2040
+ state = newState;
2041
+ stateSinceMillis = timeStamper();
2033
2042
  }
2034
2043
  if (changedState || isError) {
2035
- this._emitter.emit('dataSourceStatus', this.status);
2044
+ emitter.emit('dataSourceStatus', getStatus());
2036
2045
  }
2037
2046
  }
2038
- /**
2039
- * Requests the manager move to the provided state. This request may be ignored
2040
- * if the current state cannot transition to the requested state.
2041
- * @param state that is requested
2042
- */
2043
- requestStateUpdate(state) {
2044
- this._updateState(state);
2045
- }
2046
- /**
2047
- * Reports a datasource error to this manager. Since the {@link DataSourceStatus} includes error
2048
- * information, it is possible that that a {@link DataSourceStatus} update is emitted with
2049
- * the same {@link DataSourceState}.
2050
- *
2051
- * @param kind of the error
2052
- * @param message for the error
2053
- * @param statusCode of the error if there was one
2054
- * @param recoverable to indicate that the error is anticipated to be recoverable
2055
- */
2056
- reportError(kind, message, statusCode, recoverable = false) {
2057
- const errorInfo = {
2058
- kind,
2059
- message,
2060
- statusCode,
2061
- time: this._timeStamper(),
2062
- };
2063
- this._errorInfo = errorInfo;
2064
- this._updateState(recoverable ? exports.DataSourceState.Interrupted : exports.DataSourceState.Closed, true);
2065
- }
2047
+ return {
2048
+ get status() {
2049
+ return getStatus();
2050
+ },
2051
+ requestStateUpdate(requestedState) {
2052
+ updateState(requestedState);
2053
+ },
2054
+ reportError(kind, message, statusCode, recoverable = false) {
2055
+ errorInfo = {
2056
+ kind,
2057
+ message,
2058
+ statusCode,
2059
+ time: timeStamper(),
2060
+ };
2061
+ updateState(recoverable ? 'INTERRUPTED' : 'CLOSED', true);
2062
+ },
2063
+ // TODO: SDK-702 - Implement network availability behaviors
2064
+ // setNetworkUnavailable() {
2065
+ // updateState(DataSourceState.NetworkUnavailable);
2066
+ // },
2067
+ };
2066
2068
  }
2067
2069
 
2068
2070
  function reportClosed(logger) {
@@ -2344,8 +2346,8 @@ class BaseDataManager {
2344
2346
  this.diagnosticsManager = diagnosticsManager;
2345
2347
  this.closed = false;
2346
2348
  this.logger = config.logger;
2347
- this.dataSourceStatusManager = new DataSourceStatusManager(emitter);
2348
- this._dataSourceEventHandler = new DataSourceEventHandler(flagManager, this.dataSourceStatusManager, this.config.logger);
2349
+ this.dataSourceStatusManager = createDataSourceStatusManager(emitter);
2350
+ this._dataSourceEventHandler = createDataSourceEventHandler(flagManager, this.dataSourceStatusManager, this.config.logger);
2349
2351
  }
2350
2352
  /**
2351
2353
  * Set additional connection parameters for requests polling/streaming.
@@ -2408,16 +2410,16 @@ class BaseDataManager {
2408
2410
  return {
2409
2411
  start: () => {
2410
2412
  // update status before starting processor to ensure potential errors are reported after initializing
2411
- statusManager.requestStateUpdate(exports.DataSourceState.Initializing);
2413
+ statusManager.requestStateUpdate('INITIALIZING');
2412
2414
  processor.start();
2413
2415
  },
2414
2416
  stop: () => {
2415
2417
  processor.stop();
2416
- statusManager.requestStateUpdate(exports.DataSourceState.Closed);
2418
+ statusManager.requestStateUpdate('CLOSED');
2417
2419
  },
2418
2420
  close: () => {
2419
2421
  processor.close();
2420
- statusManager.requestStateUpdate(exports.DataSourceState.Closed);
2422
+ statusManager.requestStateUpdate('CLOSED');
2421
2423
  },
2422
2424
  };
2423
2425
  }
@@ -2429,9 +2431,10 @@ class BaseDataManager {
2429
2431
 
2430
2432
  exports.platform = jsSdkCommon__namespace;
2431
2433
  exports.BaseDataManager = BaseDataManager;
2434
+ exports.DataSourceState = DataSourceState;
2432
2435
  exports.LDClientImpl = LDClientImpl;
2433
- exports.Requestor = Requestor;
2434
2436
  exports.makeRequestor = makeRequestor;
2437
+ exports.readFlagsFromBootstrap = readFlagsFromBootstrap;
2435
2438
  exports.safeRegisterDebugOverridePlugins = safeRegisterDebugOverridePlugins;
2436
2439
  Object.keys(jsSdkCommon).forEach(function (k) {
2437
2440
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {