@launchdarkly/js-sdk-common 2.12.0 → 2.14.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 (60) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cjs/api/context/LDUser.d.ts +0 -4
  3. package/dist/cjs/api/context/LDUser.d.ts.map +1 -1
  4. package/dist/cjs/api/platform/EventSource.d.ts +1 -1
  5. package/dist/cjs/api/platform/EventSource.d.ts.map +1 -1
  6. package/dist/cjs/datasource/errors.d.ts +1 -0
  7. package/dist/cjs/datasource/errors.d.ts.map +1 -1
  8. package/dist/cjs/datasource/index.d.ts +2 -2
  9. package/dist/cjs/datasource/index.d.ts.map +1 -1
  10. package/dist/cjs/index.cjs +140 -88
  11. package/dist/cjs/index.cjs.map +1 -1
  12. package/dist/cjs/index.d.ts +2 -2
  13. package/dist/cjs/index.d.ts.map +1 -1
  14. package/dist/cjs/internal/events/EventProcessor.d.ts.map +1 -1
  15. package/dist/cjs/internal/events/InputMigrationEvent.d.ts +6 -1
  16. package/dist/cjs/internal/events/InputMigrationEvent.d.ts.map +1 -1
  17. package/dist/cjs/internal/fdv2/index.d.ts +3 -0
  18. package/dist/cjs/internal/fdv2/index.d.ts.map +1 -0
  19. package/dist/cjs/internal/fdv2/payloadReader.d.ts +58 -0
  20. package/dist/cjs/internal/fdv2/payloadReader.d.ts.map +1 -0
  21. package/dist/cjs/internal/fdv2/proto.d.ts +30 -0
  22. package/dist/cjs/internal/fdv2/proto.d.ts.map +1 -0
  23. package/dist/cjs/internal/index.d.ts +1 -1
  24. package/dist/cjs/internal/index.d.ts.map +1 -1
  25. package/dist/esm/api/context/LDUser.d.ts +0 -4
  26. package/dist/esm/api/context/LDUser.d.ts.map +1 -1
  27. package/dist/esm/api/platform/EventSource.d.ts +1 -1
  28. package/dist/esm/api/platform/EventSource.d.ts.map +1 -1
  29. package/dist/esm/datasource/errors.d.ts +1 -0
  30. package/dist/esm/datasource/errors.d.ts.map +1 -1
  31. package/dist/esm/datasource/index.d.ts +2 -2
  32. package/dist/esm/datasource/index.d.ts.map +1 -1
  33. package/dist/esm/index.d.ts +2 -2
  34. package/dist/esm/index.d.ts.map +1 -1
  35. package/dist/esm/index.mjs +140 -88
  36. package/dist/esm/index.mjs.map +1 -1
  37. package/dist/esm/internal/events/EventProcessor.d.ts.map +1 -1
  38. package/dist/esm/internal/events/InputMigrationEvent.d.ts +6 -1
  39. package/dist/esm/internal/events/InputMigrationEvent.d.ts.map +1 -1
  40. package/dist/esm/internal/fdv2/index.d.ts +3 -0
  41. package/dist/esm/internal/fdv2/index.d.ts.map +1 -0
  42. package/dist/esm/internal/fdv2/payloadReader.d.ts +58 -0
  43. package/dist/esm/internal/fdv2/payloadReader.d.ts.map +1 -0
  44. package/dist/esm/internal/fdv2/proto.d.ts +30 -0
  45. package/dist/esm/internal/fdv2/proto.d.ts.map +1 -0
  46. package/dist/esm/internal/index.d.ts +1 -1
  47. package/dist/esm/internal/index.d.ts.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/cjs/internal/stream/StreamingProcessor.d.ts +0 -39
  50. package/dist/cjs/internal/stream/StreamingProcessor.d.ts.map +0 -1
  51. package/dist/cjs/internal/stream/index.d.ts +0 -5
  52. package/dist/cjs/internal/stream/index.d.ts.map +0 -1
  53. package/dist/cjs/internal/stream/types.d.ts +0 -3
  54. package/dist/cjs/internal/stream/types.d.ts.map +0 -1
  55. package/dist/esm/internal/stream/StreamingProcessor.d.ts +0 -39
  56. package/dist/esm/internal/stream/StreamingProcessor.d.ts.map +0 -1
  57. package/dist/esm/internal/stream/index.d.ts +0 -5
  58. package/dist/esm/internal/stream/index.d.ts.map +0 -1
  59. package/dist/esm/internal/stream/types.d.ts +0 -3
  60. package/dist/esm/internal/stream/types.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
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.14.0](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.13.0...js-sdk-common-v2.14.0) (2025-03-26)
6
+
7
+
8
+ ### Features
9
+
10
+ * Support inline context for custom and migration events ([6aadf04](https://github.com/launchdarkly/js-core/commit/6aadf0463968f89bc3df10023267244c2ade1b31))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * Deprecate LDMigrationOpEvent.contextKeys in favor of LDMigrationOpEvent.context ([6aadf04](https://github.com/launchdarkly/js-core/commit/6aadf0463968f89bc3df10023267244c2ade1b31))
16
+
17
+ ## [2.13.0](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.12.0...js-sdk-common-v2.13.0) (2025-01-22)
18
+
19
+
20
+ ### Features
21
+
22
+ * Adds StreamingProcessor for FDv2 to sdk-server package. ([#707](https://github.com/launchdarkly/js-core/issues/707)) ([7f5c275](https://github.com/launchdarkly/js-core/commit/7f5c2750dcc8341d049d7e736ca21ec36e168703))
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * Remove outdated reference to geolocation. ([#719](https://github.com/launchdarkly/js-core/issues/719)) ([0eeb3b6](https://github.com/launchdarkly/js-core/commit/0eeb3b6472419d257bf52c4ab3ae33864eae1902))
28
+
5
29
  ## [2.12.0](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.11.0...js-sdk-common-v2.12.0) (2024-11-04)
6
30
 
7
31
 
@@ -35,10 +35,6 @@ export interface LDUser {
35
35
  avatar?: string;
36
36
  /**
37
37
  * The user's IP address.
38
- *
39
- * If you provide an IP, LaunchDarkly will use a geolocation service to
40
- * automatically infer a `country` for the user, unless you've already
41
- * specified one.
42
38
  */
43
39
  ip?: string;
44
40
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"LDUser.d.ts","sourceRoot":"","sources":["../../../src/api/context/LDUser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;KAC7E,CAAC;IAEF;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACvC"}
1
+ {"version":3,"file":"LDUser.d.ts","sourceRoot":"","sources":["../../../src/api/context/LDUser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;KAC7E,CAAC;IAEF;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACvC"}
@@ -1,5 +1,5 @@
1
1
  import type { HttpErrorResponse } from './Requests';
2
- export type EventName = 'delete' | 'patch' | 'ping' | 'put';
2
+ export type EventName = string;
3
3
  export type EventListener = (event?: {
4
4
  data?: any;
5
5
  }) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"EventSource.d.ts","sourceRoot":"","sources":["../../../src/api/platform/EventSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAC5D,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,GAAG,CAAA;CAAE,KAAK,IAAI,CAAC;AAC7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC;IACvC,WAAW,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzD,MAAM,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAE/D,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACjE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACjD,uBAAuB,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,EAAE,MAAM,CAAC;CAClC"}
1
+ {"version":3,"file":"EventSource.d.ts","sourceRoot":"","sources":["../../../src/api/platform/EventSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAC/B,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,GAAG,CAAA;CAAE,KAAK,IAAI,CAAC;AAC7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC;IACvC,WAAW,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzD,MAAM,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAE/D,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACjE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACjD,uBAAuB,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,EAAE,MAAM,CAAC;CAClC"}
@@ -14,4 +14,5 @@ export declare class LDStreamingError extends Error {
14
14
  readonly recoverable: boolean;
15
15
  constructor(kind: DataSourceErrorKind, message: string, code?: number, recoverable?: boolean);
16
16
  }
17
+ export type StreamingErrorHandler = (err: LDStreamingError) => void;
17
18
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/datasource/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,IAAI,EAAE,mBAAmB,CAAC;IAC1C,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChC,SAAgB,WAAW,EAAE,OAAO,CAAC;gBAEzB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,UAAO;CAO5F;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAgB,IAAI,EAAE,mBAAmB,CAAC;IAC1C,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,WAAW,EAAE,OAAO,CAAC;gBAEzB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,UAAO;CAO1F"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/datasource/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,IAAI,EAAE,mBAAmB,CAAC;IAC1C,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChC,SAAgB,WAAW,EAAE,OAAO,CAAC;gBAEzB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,UAAO;CAO5F;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAgB,IAAI,EAAE,mBAAmB,CAAC;IAC1C,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,WAAW,EAAE,OAAO,CAAC;gBAEzB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,UAAO;CAO1F;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import { DataSourceErrorKind } from './DataSourceErrorKinds';
2
- import { LDFileDataSourceError, LDPollingError, LDStreamingError } from './errors';
3
- export { DataSourceErrorKind, LDFileDataSourceError, LDPollingError, LDStreamingError };
2
+ import { LDFileDataSourceError, LDPollingError, LDStreamingError, StreamingErrorHandler } from './errors';
3
+ export { DataSourceErrorKind, LDFileDataSourceError, LDPollingError, LDStreamingError, StreamingErrorHandler, };
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/datasource/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEnF,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/datasource/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,GACtB,CAAC"}
@@ -2066,6 +2066,7 @@ class EventProcessor {
2066
2066
  if (shouldSample(inputEvent.samplingRatio)) {
2067
2067
  const migrationEvent = {
2068
2068
  ...inputEvent,
2069
+ context: inputEvent.context ? this._contextFilter.filter(inputEvent.context) : undefined,
2069
2070
  };
2070
2071
  if (migrationEvent.samplingRatio === 1) {
2071
2072
  delete migrationEvent.samplingRatio;
@@ -2147,7 +2148,7 @@ class EventProcessor {
2147
2148
  kind: 'custom',
2148
2149
  creationDate: event.creationDate,
2149
2150
  key: event.key,
2150
- contextKeys: event.context.kindsAndKeys,
2151
+ context: this._contextFilter.filter(event.context),
2151
2152
  };
2152
2153
  if (event.samplingRatio !== 1) {
2153
2154
  out.samplingRatio = event.samplingRatio;
@@ -2326,104 +2327,155 @@ class EventFactoryBase {
2326
2327
  }
2327
2328
  }
2328
2329
 
2329
- const reportJsonError = (type, data, logger, errorHandler) => {
2330
- logger?.error(`Stream received invalid data in "${type}" message`);
2331
- logger?.debug(`Invalid JSON follows: ${data}`);
2332
- errorHandler?.(new LDStreamingError(exports.DataSourceErrorKind.InvalidData, 'Malformed JSON data in event stream'));
2333
- };
2334
- // TODO: SDK-156 - Move to Server SDK specific location
2335
- class StreamingProcessor {
2336
- constructor(clientContext, streamUriPath, parameters, _listeners, baseHeaders, _diagnosticsManager, _errorHandler, _streamInitialReconnectDelay = 1) {
2337
- this._listeners = _listeners;
2338
- this._diagnosticsManager = _diagnosticsManager;
2339
- this._errorHandler = _errorHandler;
2340
- this._streamInitialReconnectDelay = _streamInitialReconnectDelay;
2341
- const { basicConfiguration, platform } = clientContext;
2342
- const { logger } = basicConfiguration;
2343
- const { requests } = platform;
2344
- this._headers = { ...baseHeaders };
2345
- this._logger = logger;
2346
- this._requests = requests;
2347
- this._streamUri = getStreamingUri(basicConfiguration.serviceEndpoints, streamUriPath, parameters);
2348
- }
2349
- _logConnectionStarted() {
2350
- this._connectionAttemptStartTime = Date.now();
2351
- }
2352
- _logConnectionResult(success) {
2353
- if (this._connectionAttemptStartTime && this._diagnosticsManager) {
2354
- this._diagnosticsManager.recordStreamInit(this._connectionAttemptStartTime, !success, Date.now() - this._connectionAttemptStartTime);
2355
- }
2356
- this._connectionAttemptStartTime = undefined;
2357
- }
2330
+ /**
2331
+ * A FDv2 PayloadReader can be used to parse payloads from a stream of FDv2 events. It will send payloads
2332
+ * to the PayloadListeners as the payloads are received. Invalid series of events may be dropped silently,
2333
+ * but the payload reader will continue to operate.
2334
+ */
2335
+ class PayloadReader {
2358
2336
  /**
2359
- * This is a wrapper around the passed errorHandler which adds additional
2360
- * diagnostics and logging logic.
2361
- *
2362
- * @param err The error to be logged and handled.
2363
- * @return boolean whether to retry the connection.
2337
+ * Creates a PayloadReader
2364
2338
  *
2365
- * @private
2339
+ * @param eventStream event stream of FDv2 events
2340
+ * @param _objProcessors defines object processors for each object kind.
2341
+ * @param _errorHandler that will be called with errors as they are encountered
2342
+ * @param _logger for logging
2366
2343
  */
2367
- _retryAndHandleError(err) {
2368
- if (!shouldRetry(err)) {
2369
- this._logConnectionResult(false);
2370
- this._errorHandler?.(new LDStreamingError(exports.DataSourceErrorKind.ErrorResponse, err.message, err.status));
2371
- this._logger?.error(httpErrorMessage(err, 'streaming request'));
2372
- return false;
2373
- }
2374
- this._logger?.warn(httpErrorMessage(err, 'streaming request', 'will retry'));
2375
- this._logConnectionResult(false);
2376
- this._logConnectionStarted();
2377
- return true;
2378
- }
2379
- start() {
2380
- this._logConnectionStarted();
2381
- // TLS is handled by the platform implementation.
2382
- const eventSource = this._requests.createEventSource(this._streamUri, {
2383
- headers: this._headers,
2384
- errorFilter: (error) => this._retryAndHandleError(error),
2385
- initialRetryDelayMillis: 1000 * this._streamInitialReconnectDelay,
2386
- readTimeoutMillis: 5 * 60 * 1000,
2387
- retryResetIntervalMillis: 60 * 1000,
2388
- });
2389
- this._eventSource = eventSource;
2390
- eventSource.onclose = () => {
2391
- this._logger?.info('Closed LaunchDarkly stream connection');
2344
+ constructor(eventStream, _objProcessors, _errorHandler, _logger) {
2345
+ this._objProcessors = _objProcessors;
2346
+ this._errorHandler = _errorHandler;
2347
+ this._logger = _logger;
2348
+ this._listeners = [];
2349
+ this._tempId = undefined;
2350
+ this._tempBasis = undefined;
2351
+ this._tempUpdates = [];
2352
+ this._processServerIntent = (data) => {
2353
+ // clear state in prep for handling data
2354
+ this._resetState();
2355
+ // if there's no payloads, return
2356
+ if (!data.payloads.length) {
2357
+ return;
2358
+ }
2359
+ // at the time of writing this, it was agreed upon that SDKs could assume exactly 1 element in this list. In the future, a negotiation of protocol version will be required to remove this assumption.
2360
+ const payload = data.payloads[0];
2361
+ switch (payload?.code) {
2362
+ case 'xfer-full':
2363
+ this._tempBasis = true;
2364
+ break;
2365
+ case 'xfer-changes':
2366
+ case 'none':
2367
+ this._tempBasis = false;
2368
+ break;
2369
+ default:
2370
+ // unrecognized intent code, return
2371
+ return;
2372
+ }
2373
+ this._tempId = payload?.id;
2374
+ };
2375
+ this._processPutObject = (data) => {
2376
+ // if the following properties haven't been provided by now, we should ignore the event
2377
+ if (!this._tempId || // server intent hasn't been recieved yet.
2378
+ !data.kind ||
2379
+ !data.key ||
2380
+ !data.version ||
2381
+ !data.object) {
2382
+ return;
2383
+ }
2384
+ const obj = this._processObj(data.kind, data.object);
2385
+ if (!obj) {
2386
+ this._logger?.warn(`Unable to prcoess object for kind: '${data.kind}'`);
2387
+ // ignore unrecognized kinds
2388
+ return;
2389
+ }
2390
+ this._tempUpdates.push({
2391
+ kind: data.kind,
2392
+ key: data.key,
2393
+ version: data.version,
2394
+ object: obj,
2395
+ // intentionally omit deleted for this put
2396
+ });
2397
+ };
2398
+ this._processDeleteObject = (data) => {
2399
+ // if the following properties haven't been provided by now, we should ignore the event
2400
+ if (!this._tempId || !data.kind || !data.key || !data.version) {
2401
+ return;
2402
+ }
2403
+ this._tempUpdates.push({
2404
+ kind: data.kind,
2405
+ key: data.key,
2406
+ version: data.version,
2407
+ // intentionally omit object for this delete
2408
+ deleted: true,
2409
+ });
2392
2410
  };
2393
- eventSource.onerror = () => {
2394
- // The work is done by `errorFilter`.
2411
+ this._processPayloadTransferred = (data) => {
2412
+ // if the following properties haven't been provided by now, we should reset
2413
+ if (!this._tempId || // server intent hasn't been recieved yet.
2414
+ !data.state ||
2415
+ !data.version ||
2416
+ this._tempBasis === undefined) {
2417
+ this._resetState(); // a reset is best defensive action since payload transferred terminates a payload
2418
+ return;
2419
+ }
2420
+ const payload = {
2421
+ id: this._tempId,
2422
+ version: data.version,
2423
+ state: data.state,
2424
+ basis: this._tempBasis,
2425
+ updates: this._tempUpdates,
2426
+ };
2427
+ this._listeners.forEach((it) => it(payload));
2428
+ this._resetState();
2395
2429
  };
2396
- eventSource.onopen = () => {
2397
- this._logger?.info('Opened LaunchDarkly stream connection');
2430
+ this._processGoodbye = (data) => {
2431
+ this._logger?.info(`Goodbye was received from the LaunchDarkly connection with reason: ${data.reason}.`);
2432
+ this._resetState();
2398
2433
  };
2399
- eventSource.onretrying = (e) => {
2400
- this._logger?.info(`Will retry stream connection in ${e.delayMillis} milliseconds`);
2434
+ this._processError = (data) => {
2435
+ this._logger?.info(`An issue was encountered receiving updates for payload ${this._tempId} with reason: ${data.reason}. Automatic retry will occur.`);
2436
+ this._resetState();
2401
2437
  };
2402
- this._listeners.forEach(({ deserializeData, processJson }, eventName) => {
2403
- eventSource.addEventListener(eventName, (event) => {
2404
- this._logger?.debug(`Received ${eventName} event`);
2405
- if (event?.data) {
2406
- this._logConnectionResult(true);
2407
- const { data } = event;
2408
- const dataJson = deserializeData(data);
2409
- if (!dataJson) {
2410
- reportJsonError(eventName, data, this._logger, this._errorHandler);
2411
- return;
2412
- }
2413
- processJson(dataJson);
2438
+ this._attachHandler(eventStream, 'server-intent', this._processServerIntent);
2439
+ this._attachHandler(eventStream, 'put-object', this._processPutObject);
2440
+ this._attachHandler(eventStream, 'delete-object', this._processDeleteObject);
2441
+ this._attachHandler(eventStream, 'payload-transferred', this._processPayloadTransferred);
2442
+ this._attachHandler(eventStream, 'goodbye', this._processGoodbye);
2443
+ this._attachHandler(eventStream, 'error', this._processError);
2444
+ }
2445
+ addPayloadListener(listener) {
2446
+ this._listeners.push(listener);
2447
+ }
2448
+ removePayloadListener(listener) {
2449
+ const index = this._listeners.indexOf(listener, 0);
2450
+ if (index > -1) {
2451
+ this._listeners.splice(index, 1);
2452
+ }
2453
+ }
2454
+ _attachHandler(stream, eventName, processor) {
2455
+ stream.addEventListener(eventName, async (event) => {
2456
+ if (event?.data) {
2457
+ this._logger?.debug(`Received ${eventName} event. Data is ${event.data}`);
2458
+ try {
2459
+ processor(JSON.parse(event.data));
2414
2460
  }
2415
- else {
2416
- this._errorHandler?.(new LDStreamingError(exports.DataSourceErrorKind.Unknown, 'Unexpected payload from event stream'));
2461
+ catch {
2462
+ this._logger?.error(`Stream received data that was unable to be processed in "${eventName}" message`);
2463
+ this._logger?.debug(`Data follows: ${event.data}`);
2464
+ this._errorHandler?.(exports.DataSourceErrorKind.InvalidData, 'Malformed data in event stream');
2417
2465
  }
2418
- });
2466
+ }
2467
+ else {
2468
+ this._errorHandler?.(exports.DataSourceErrorKind.Unknown, 'Unexpected message from event stream');
2469
+ }
2419
2470
  });
2420
2471
  }
2421
- stop() {
2422
- this._eventSource?.close();
2423
- this._eventSource = undefined;
2472
+ _processObj(kind, jsonObj) {
2473
+ return this._objProcessors[kind]?.(jsonObj);
2424
2474
  }
2425
- close() {
2426
- this.stop();
2475
+ _resetState() {
2476
+ this._tempId = undefined;
2477
+ this._tempBasis = undefined;
2478
+ this._tempUpdates = [];
2427
2479
  }
2428
2480
  }
2429
2481
 
@@ -2438,7 +2490,7 @@ var index = /*#__PURE__*/Object.freeze({
2438
2490
  InputEvalEvent: InputEvalEvent,
2439
2491
  InputIdentifyEvent: InputIdentifyEvent,
2440
2492
  NullEventProcessor: NullEventProcessor,
2441
- StreamingProcessor: StreamingProcessor,
2493
+ PayloadReader: PayloadReader,
2442
2494
  isLegacyUser: isLegacyUser,
2443
2495
  isMultiKind: isMultiKind,
2444
2496
  isSingleKind: isSingleKind,