@launchdarkly/js-sdk-common 2.12.0 → 2.13.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 (54) hide show
  1. package/CHANGELOG.md +12 -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 +138 -87
  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/fdv2/index.d.ts +3 -0
  15. package/dist/cjs/internal/fdv2/index.d.ts.map +1 -0
  16. package/dist/cjs/internal/fdv2/payloadReader.d.ts +58 -0
  17. package/dist/cjs/internal/fdv2/payloadReader.d.ts.map +1 -0
  18. package/dist/cjs/internal/fdv2/proto.d.ts +30 -0
  19. package/dist/cjs/internal/fdv2/proto.d.ts.map +1 -0
  20. package/dist/cjs/internal/index.d.ts +1 -1
  21. package/dist/cjs/internal/index.d.ts.map +1 -1
  22. package/dist/esm/api/context/LDUser.d.ts +0 -4
  23. package/dist/esm/api/context/LDUser.d.ts.map +1 -1
  24. package/dist/esm/api/platform/EventSource.d.ts +1 -1
  25. package/dist/esm/api/platform/EventSource.d.ts.map +1 -1
  26. package/dist/esm/datasource/errors.d.ts +1 -0
  27. package/dist/esm/datasource/errors.d.ts.map +1 -1
  28. package/dist/esm/datasource/index.d.ts +2 -2
  29. package/dist/esm/datasource/index.d.ts.map +1 -1
  30. package/dist/esm/index.d.ts +2 -2
  31. package/dist/esm/index.d.ts.map +1 -1
  32. package/dist/esm/index.mjs +138 -87
  33. package/dist/esm/index.mjs.map +1 -1
  34. package/dist/esm/internal/fdv2/index.d.ts +3 -0
  35. package/dist/esm/internal/fdv2/index.d.ts.map +1 -0
  36. package/dist/esm/internal/fdv2/payloadReader.d.ts +58 -0
  37. package/dist/esm/internal/fdv2/payloadReader.d.ts.map +1 -0
  38. package/dist/esm/internal/fdv2/proto.d.ts +30 -0
  39. package/dist/esm/internal/fdv2/proto.d.ts.map +1 -0
  40. package/dist/esm/internal/index.d.ts +1 -1
  41. package/dist/esm/internal/index.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/cjs/internal/stream/StreamingProcessor.d.ts +0 -39
  44. package/dist/cjs/internal/stream/StreamingProcessor.d.ts.map +0 -1
  45. package/dist/cjs/internal/stream/index.d.ts +0 -5
  46. package/dist/cjs/internal/stream/index.d.ts.map +0 -1
  47. package/dist/cjs/internal/stream/types.d.ts +0 -3
  48. package/dist/cjs/internal/stream/types.d.ts.map +0 -1
  49. package/dist/esm/internal/stream/StreamingProcessor.d.ts +0 -39
  50. package/dist/esm/internal/stream/StreamingProcessor.d.ts.map +0 -1
  51. package/dist/esm/internal/stream/index.d.ts +0 -5
  52. package/dist/esm/internal/stream/index.d.ts.map +0 -1
  53. package/dist/esm/internal/stream/types.d.ts +0 -3
  54. package/dist/esm/internal/stream/types.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
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.13.0](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.12.0...js-sdk-common-v2.13.0) (2025-01-22)
6
+
7
+
8
+ ### Features
9
+
10
+ * 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))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * Remove outdated reference to geolocation. ([#719](https://github.com/launchdarkly/js-core/issues/719)) ([0eeb3b6](https://github.com/launchdarkly/js-core/commit/0eeb3b6472419d257bf52c4ab3ae33864eae1902))
16
+
5
17
  ## [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
18
 
7
19
 
@@ -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"}
@@ -2326,104 +2326,155 @@ class EventFactoryBase {
2326
2326
  }
2327
2327
  }
2328
2328
 
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
- }
2329
+ /**
2330
+ * A FDv2 PayloadReader can be used to parse payloads from a stream of FDv2 events. It will send payloads
2331
+ * to the PayloadListeners as the payloads are received. Invalid series of events may be dropped silently,
2332
+ * but the payload reader will continue to operate.
2333
+ */
2334
+ class PayloadReader {
2358
2335
  /**
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.
2336
+ * Creates a PayloadReader
2364
2337
  *
2365
- * @private
2338
+ * @param eventStream event stream of FDv2 events
2339
+ * @param _objProcessors defines object processors for each object kind.
2340
+ * @param _errorHandler that will be called with errors as they are encountered
2341
+ * @param _logger for logging
2366
2342
  */
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');
2343
+ constructor(eventStream, _objProcessors, _errorHandler, _logger) {
2344
+ this._objProcessors = _objProcessors;
2345
+ this._errorHandler = _errorHandler;
2346
+ this._logger = _logger;
2347
+ this._listeners = [];
2348
+ this._tempId = undefined;
2349
+ this._tempBasis = undefined;
2350
+ this._tempUpdates = [];
2351
+ this._processServerIntent = (data) => {
2352
+ // clear state in prep for handling data
2353
+ this._resetState();
2354
+ // if there's no payloads, return
2355
+ if (!data.payloads.length) {
2356
+ return;
2357
+ }
2358
+ // 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.
2359
+ const payload = data.payloads[0];
2360
+ switch (payload?.code) {
2361
+ case 'xfer-full':
2362
+ this._tempBasis = true;
2363
+ break;
2364
+ case 'xfer-changes':
2365
+ case 'none':
2366
+ this._tempBasis = false;
2367
+ break;
2368
+ default:
2369
+ // unrecognized intent code, return
2370
+ return;
2371
+ }
2372
+ this._tempId = payload?.id;
2392
2373
  };
2393
- eventSource.onerror = () => {
2394
- // The work is done by `errorFilter`.
2374
+ this._processPutObject = (data) => {
2375
+ // if the following properties haven't been provided by now, we should ignore the event
2376
+ if (!this._tempId || // server intent hasn't been recieved yet.
2377
+ !data.kind ||
2378
+ !data.key ||
2379
+ !data.version ||
2380
+ !data.object) {
2381
+ return;
2382
+ }
2383
+ const obj = this._processObj(data.kind, data.object);
2384
+ if (!obj) {
2385
+ this._logger?.warn(`Unable to prcoess object for kind: '${data.kind}'`);
2386
+ // ignore unrecognized kinds
2387
+ return;
2388
+ }
2389
+ this._tempUpdates.push({
2390
+ kind: data.kind,
2391
+ key: data.key,
2392
+ version: data.version,
2393
+ object: obj,
2394
+ // intentionally omit deleted for this put
2395
+ });
2395
2396
  };
2396
- eventSource.onopen = () => {
2397
- this._logger?.info('Opened LaunchDarkly stream connection');
2397
+ this._processDeleteObject = (data) => {
2398
+ // if the following properties haven't been provided by now, we should ignore the event
2399
+ if (!this._tempId || !data.kind || !data.key || !data.version) {
2400
+ return;
2401
+ }
2402
+ this._tempUpdates.push({
2403
+ kind: data.kind,
2404
+ key: data.key,
2405
+ version: data.version,
2406
+ // intentionally omit object for this delete
2407
+ deleted: true,
2408
+ });
2398
2409
  };
2399
- eventSource.onretrying = (e) => {
2400
- this._logger?.info(`Will retry stream connection in ${e.delayMillis} milliseconds`);
2410
+ this._processPayloadTransferred = (data) => {
2411
+ // if the following properties haven't been provided by now, we should reset
2412
+ if (!this._tempId || // server intent hasn't been recieved yet.
2413
+ !data.state ||
2414
+ !data.version ||
2415
+ this._tempBasis === undefined) {
2416
+ this._resetState(); // a reset is best defensive action since payload transferred terminates a payload
2417
+ return;
2418
+ }
2419
+ const payload = {
2420
+ id: this._tempId,
2421
+ version: data.version,
2422
+ state: data.state,
2423
+ basis: this._tempBasis,
2424
+ updates: this._tempUpdates,
2425
+ };
2426
+ this._listeners.forEach((it) => it(payload));
2427
+ this._resetState();
2401
2428
  };
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);
2429
+ this._processGoodbye = (data) => {
2430
+ this._logger?.info(`Goodbye was received from the LaunchDarkly connection with reason: ${data.reason}.`);
2431
+ this._resetState();
2432
+ };
2433
+ this._processError = (data) => {
2434
+ this._logger?.info(`An issue was encountered receiving updates for payload ${this._tempId} with reason: ${data.reason}. Automatic retry will occur.`);
2435
+ this._resetState();
2436
+ };
2437
+ this._attachHandler(eventStream, 'server-intent', this._processServerIntent);
2438
+ this._attachHandler(eventStream, 'put-object', this._processPutObject);
2439
+ this._attachHandler(eventStream, 'delete-object', this._processDeleteObject);
2440
+ this._attachHandler(eventStream, 'payload-transferred', this._processPayloadTransferred);
2441
+ this._attachHandler(eventStream, 'goodbye', this._processGoodbye);
2442
+ this._attachHandler(eventStream, 'error', this._processError);
2443
+ }
2444
+ addPayloadListener(listener) {
2445
+ this._listeners.push(listener);
2446
+ }
2447
+ removePayloadListener(listener) {
2448
+ const index = this._listeners.indexOf(listener, 0);
2449
+ if (index > -1) {
2450
+ this._listeners.splice(index, 1);
2451
+ }
2452
+ }
2453
+ _attachHandler(stream, eventName, processor) {
2454
+ stream.addEventListener(eventName, async (event) => {
2455
+ if (event?.data) {
2456
+ this._logger?.debug(`Received ${eventName} event. Data is ${event.data}`);
2457
+ try {
2458
+ processor(JSON.parse(event.data));
2414
2459
  }
2415
- else {
2416
- this._errorHandler?.(new LDStreamingError(exports.DataSourceErrorKind.Unknown, 'Unexpected payload from event stream'));
2460
+ catch {
2461
+ this._logger?.error(`Stream received data that was unable to be processed in "${eventName}" message`);
2462
+ this._logger?.debug(`Data follows: ${event.data}`);
2463
+ this._errorHandler?.(exports.DataSourceErrorKind.InvalidData, 'Malformed data in event stream');
2417
2464
  }
2418
- });
2465
+ }
2466
+ else {
2467
+ this._errorHandler?.(exports.DataSourceErrorKind.Unknown, 'Unexpected message from event stream');
2468
+ }
2419
2469
  });
2420
2470
  }
2421
- stop() {
2422
- this._eventSource?.close();
2423
- this._eventSource = undefined;
2471
+ _processObj(kind, jsonObj) {
2472
+ return this._objProcessors[kind]?.(jsonObj);
2424
2473
  }
2425
- close() {
2426
- this.stop();
2474
+ _resetState() {
2475
+ this._tempId = undefined;
2476
+ this._tempBasis = undefined;
2477
+ this._tempUpdates = [];
2427
2478
  }
2428
2479
  }
2429
2480
 
@@ -2438,7 +2489,7 @@ var index = /*#__PURE__*/Object.freeze({
2438
2489
  InputEvalEvent: InputEvalEvent,
2439
2490
  InputIdentifyEvent: InputIdentifyEvent,
2440
2491
  NullEventProcessor: NullEventProcessor,
2441
- StreamingProcessor: StreamingProcessor,
2492
+ PayloadReader: PayloadReader,
2442
2493
  isLegacyUser: isLegacyUser,
2443
2494
  isMultiKind: isMultiKind,
2444
2495
  isSingleKind: isSingleKind,