@metamask-previews/core-backend 6.2.2-preview-fbc0aed37 → 6.2.2-preview-e5cef32c6

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 (98) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/api/base-client.cjs +5 -3
  3. package/dist/api/base-client.cjs.map +1 -1
  4. package/dist/api/base-client.d.cts +1 -1
  5. package/dist/api/base-client.d.cts.map +1 -1
  6. package/dist/api/base-client.d.mts +1 -1
  7. package/dist/api/base-client.d.mts.map +1 -1
  8. package/dist/api/base-client.mjs +5 -3
  9. package/dist/api/base-client.mjs.map +1 -1
  10. package/dist/index.cjs +10 -3
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +6 -4
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.mts +6 -4
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +6 -2
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/ws/AccountActivityService-method-action-types.cjs.map +1 -0
  19. package/dist/ws/AccountActivityService-method-action-types.d.cts.map +1 -0
  20. package/dist/ws/AccountActivityService-method-action-types.d.mts.map +1 -0
  21. package/dist/ws/AccountActivityService-method-action-types.mjs.map +1 -0
  22. package/dist/{AccountActivityService.cjs → ws/AccountActivityService.cjs} +1 -1
  23. package/dist/ws/AccountActivityService.cjs.map +1 -0
  24. package/dist/{AccountActivityService.d.cts → ws/AccountActivityService.d.cts} +1 -1
  25. package/dist/ws/AccountActivityService.d.cts.map +1 -0
  26. package/dist/{AccountActivityService.d.mts → ws/AccountActivityService.d.mts} +1 -1
  27. package/dist/ws/AccountActivityService.d.mts.map +1 -0
  28. package/dist/{AccountActivityService.mjs → ws/AccountActivityService.mjs} +1 -1
  29. package/dist/ws/AccountActivityService.mjs.map +1 -0
  30. package/dist/ws/BackendWebSocketService-method-action-types.cjs.map +1 -0
  31. package/dist/ws/BackendWebSocketService-method-action-types.d.cts.map +1 -0
  32. package/dist/ws/BackendWebSocketService-method-action-types.d.mts.map +1 -0
  33. package/dist/ws/BackendWebSocketService-method-action-types.mjs.map +1 -0
  34. package/dist/{BackendWebSocketService.cjs → ws/BackendWebSocketService.cjs} +1 -1
  35. package/dist/ws/BackendWebSocketService.cjs.map +1 -0
  36. package/dist/ws/BackendWebSocketService.d.cts.map +1 -0
  37. package/dist/ws/BackendWebSocketService.d.mts.map +1 -0
  38. package/dist/{BackendWebSocketService.mjs → ws/BackendWebSocketService.mjs} +1 -1
  39. package/dist/ws/BackendWebSocketService.mjs.map +1 -0
  40. package/dist/ws/ohlcv/OHLCVService-method-action-types.cjs +7 -0
  41. package/dist/ws/ohlcv/OHLCVService-method-action-types.cjs.map +1 -0
  42. package/dist/ws/ohlcv/OHLCVService-method-action-types.d.cts +35 -0
  43. package/dist/ws/ohlcv/OHLCVService-method-action-types.d.cts.map +1 -0
  44. package/dist/ws/ohlcv/OHLCVService-method-action-types.d.mts +35 -0
  45. package/dist/ws/ohlcv/OHLCVService-method-action-types.d.mts.map +1 -0
  46. package/dist/ws/ohlcv/OHLCVService-method-action-types.mjs +6 -0
  47. package/dist/ws/ohlcv/OHLCVService-method-action-types.mjs.map +1 -0
  48. package/dist/ws/ohlcv/OHLCVService.cjs +359 -0
  49. package/dist/ws/ohlcv/OHLCVService.cjs.map +1 -0
  50. package/dist/ws/ohlcv/OHLCVService.d.cts +109 -0
  51. package/dist/ws/ohlcv/OHLCVService.d.cts.map +1 -0
  52. package/dist/ws/ohlcv/OHLCVService.d.mts +109 -0
  53. package/dist/ws/ohlcv/OHLCVService.d.mts.map +1 -0
  54. package/dist/ws/ohlcv/OHLCVService.mjs +355 -0
  55. package/dist/ws/ohlcv/OHLCVService.mjs.map +1 -0
  56. package/dist/ws/ohlcv/index.cjs +9 -0
  57. package/dist/ws/ohlcv/index.cjs.map +1 -0
  58. package/dist/ws/ohlcv/index.d.cts +5 -0
  59. package/dist/ws/ohlcv/index.d.cts.map +1 -0
  60. package/dist/ws/ohlcv/index.d.mts +5 -0
  61. package/dist/ws/ohlcv/index.d.mts.map +1 -0
  62. package/dist/ws/ohlcv/index.mjs +3 -0
  63. package/dist/ws/ohlcv/index.mjs.map +1 -0
  64. package/dist/ws/ohlcv/types.cjs +6 -0
  65. package/dist/ws/ohlcv/types.cjs.map +1 -0
  66. package/dist/ws/ohlcv/types.d.cts +32 -0
  67. package/dist/ws/ohlcv/types.d.cts.map +1 -0
  68. package/dist/ws/ohlcv/types.d.mts +32 -0
  69. package/dist/ws/ohlcv/types.d.mts.map +1 -0
  70. package/dist/ws/ohlcv/types.mjs +5 -0
  71. package/dist/ws/ohlcv/types.mjs.map +1 -0
  72. package/package.json +3 -2
  73. package/dist/AccountActivityService-method-action-types.cjs.map +0 -1
  74. package/dist/AccountActivityService-method-action-types.d.cts.map +0 -1
  75. package/dist/AccountActivityService-method-action-types.d.mts.map +0 -1
  76. package/dist/AccountActivityService-method-action-types.mjs.map +0 -1
  77. package/dist/AccountActivityService.cjs.map +0 -1
  78. package/dist/AccountActivityService.d.cts.map +0 -1
  79. package/dist/AccountActivityService.d.mts.map +0 -1
  80. package/dist/AccountActivityService.mjs.map +0 -1
  81. package/dist/BackendWebSocketService-method-action-types.cjs.map +0 -1
  82. package/dist/BackendWebSocketService-method-action-types.d.cts.map +0 -1
  83. package/dist/BackendWebSocketService-method-action-types.d.mts.map +0 -1
  84. package/dist/BackendWebSocketService-method-action-types.mjs.map +0 -1
  85. package/dist/BackendWebSocketService.cjs.map +0 -1
  86. package/dist/BackendWebSocketService.d.cts.map +0 -1
  87. package/dist/BackendWebSocketService.d.mts.map +0 -1
  88. package/dist/BackendWebSocketService.mjs.map +0 -1
  89. /package/dist/{AccountActivityService-method-action-types.cjs → ws/AccountActivityService-method-action-types.cjs} +0 -0
  90. /package/dist/{AccountActivityService-method-action-types.d.cts → ws/AccountActivityService-method-action-types.d.cts} +0 -0
  91. /package/dist/{AccountActivityService-method-action-types.d.mts → ws/AccountActivityService-method-action-types.d.mts} +0 -0
  92. /package/dist/{AccountActivityService-method-action-types.mjs → ws/AccountActivityService-method-action-types.mjs} +0 -0
  93. /package/dist/{BackendWebSocketService-method-action-types.cjs → ws/BackendWebSocketService-method-action-types.cjs} +0 -0
  94. /package/dist/{BackendWebSocketService-method-action-types.d.cts → ws/BackendWebSocketService-method-action-types.d.cts} +0 -0
  95. /package/dist/{BackendWebSocketService-method-action-types.d.mts → ws/BackendWebSocketService-method-action-types.d.mts} +0 -0
  96. /package/dist/{BackendWebSocketService-method-action-types.mjs → ws/BackendWebSocketService-method-action-types.mjs} +0 -0
  97. /package/dist/{BackendWebSocketService.d.cts → ws/BackendWebSocketService.d.cts} +0 -0
  98. /package/dist/{BackendWebSocketService.d.mts → ws/BackendWebSocketService.d.mts} +0 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * OHLCV Service for real-time candlestick data streaming via WebSocket.
3
+ *
4
+ * Wraps {@link BackendWebSocketService} through the messenger pattern to
5
+ * provide subscribe/unsubscribe semantics for OHLCV market-data channels.
6
+ * Includes reference counting, grace-period unsubscribe, idempotency checks,
7
+ * chain-status forwarding, and automatic resubscription on reconnect.
8
+ */
9
+ import type { TraceCallback } from "@metamask/controller-utils";
10
+ import type { Messenger } from "@metamask/messenger";
11
+ import type { BackendWebSocketServiceConnectionStateChangedEvent } from "../BackendWebSocketService.mjs";
12
+ import type { BackendWebSocketServiceMethodActions } from "../BackendWebSocketService-method-action-types.mjs";
13
+ import type { OHLCVServiceMethodActions } from "./OHLCVService-method-action-types.mjs";
14
+ import type { OHLCVBar, OHLCVSubscriptionOptions } from "./types.mjs";
15
+ declare const SERVICE_NAME = "OHLCVService";
16
+ /**
17
+ * System notification data for chain status updates on market-data channels.
18
+ */
19
+ export type OHLCVSystemNotificationData = {
20
+ chainIds: string[];
21
+ status: 'down' | 'up';
22
+ timestamp?: number;
23
+ };
24
+ /**
25
+ * Configuration options for the OHLCV service.
26
+ */
27
+ export type OHLCVServiceOptions = {
28
+ /** Optional callback to trace performance of OHLCV operations (default: no-op) */
29
+ traceFn?: TraceCallback;
30
+ };
31
+ export type OHLCVServiceActions = OHLCVServiceMethodActions;
32
+ export declare const OHLCV_SERVICE_ALLOWED_ACTIONS: readonly ["BackendWebSocketService:connect", "BackendWebSocketService:forceReconnection", "BackendWebSocketService:subscribe", "BackendWebSocketService:getConnectionInfo", "BackendWebSocketService:channelHasSubscription", "BackendWebSocketService:getSubscriptionsByChannel", "BackendWebSocketService:findSubscriptionsByChannelPrefix", "BackendWebSocketService:addChannelCallback", "BackendWebSocketService:removeChannelCallback"];
33
+ export declare const OHLCV_SERVICE_ALLOWED_EVENTS: readonly ["BackendWebSocketService:connectionStateChanged"];
34
+ export type AllowedActions = BackendWebSocketServiceMethodActions;
35
+ export type OHLCVServiceBarUpdatedEvent = {
36
+ type: `OHLCVService:barUpdated`;
37
+ payload: [{
38
+ channel: string;
39
+ bar: OHLCVBar;
40
+ }];
41
+ };
42
+ export type OHLCVServiceChainStatusChangedEvent = {
43
+ type: `OHLCVService:chainStatusChanged`;
44
+ payload: [{
45
+ chainIds: string[];
46
+ status: 'up' | 'down';
47
+ timestamp?: number;
48
+ }];
49
+ };
50
+ export type OHLCVServiceSubscriptionErrorEvent = {
51
+ type: `OHLCVService:subscriptionError`;
52
+ payload: [{
53
+ channel: string;
54
+ error: string;
55
+ operation: string;
56
+ }];
57
+ };
58
+ export type OHLCVServiceEvents = OHLCVServiceBarUpdatedEvent | OHLCVServiceChainStatusChangedEvent | OHLCVServiceSubscriptionErrorEvent;
59
+ export type AllowedEvents = BackendWebSocketServiceConnectionStateChangedEvent;
60
+ export type OHLCVServiceMessenger = Messenger<typeof SERVICE_NAME, OHLCVServiceActions | AllowedActions, OHLCVServiceEvents | AllowedEvents>;
61
+ /**
62
+ * Service for real-time OHLCV candlestick streaming via the backend WebSocket
63
+ * gateway. Communicates with {@link BackendWebSocketService} exclusively
64
+ * through the messenger — no direct import of the class.
65
+ *
66
+ * Features:
67
+ * - Reference counting: multiple UI consumers share one WebSocket subscription
68
+ * - Grace-period unsubscribe: avoids rapid unsub/resub during navigation
69
+ * - Idempotency: duplicate subscribe calls for the same channel are no-ops
70
+ * - Reconnect resilience: resubscribes all active channels on reconnect
71
+ * - Chain-status forwarding: listens to system-notifications for chain up/down
72
+ *
73
+ */
74
+ export declare class OHLCVService {
75
+ #private;
76
+ readonly name = "OHLCVService";
77
+ constructor(options: OHLCVServiceOptions & {
78
+ messenger: OHLCVServiceMessenger;
79
+ });
80
+ /**
81
+ * Register the system-notifications channel callback.
82
+ */
83
+ init(): void;
84
+ /**
85
+ * Subscribe to an OHLCV channel. If this is the first subscriber for the
86
+ * given asset/interval/currency combination a WebSocket subscription is
87
+ * created. Additional calls for the same combination only bump the reference
88
+ * count.
89
+ *
90
+ * @param options - The subscription parameters.
91
+ * @returns A promise that resolves once the subscription is established.
92
+ */
93
+ subscribe(options: OHLCVSubscriptionOptions): Promise<void>;
94
+ /**
95
+ * Unsubscribe from an OHLCV channel. Decrements the reference count and,
96
+ * when it reaches zero, starts a grace-period timer before actually
97
+ * unsubscribing from the WebSocket to absorb rapid navigation patterns.
98
+ *
99
+ * @param options - The subscription parameters to unsubscribe from.
100
+ * @returns A promise that resolves once the unsubscription is processed.
101
+ */
102
+ unsubscribe(options: OHLCVSubscriptionOptions): Promise<void>;
103
+ /**
104
+ * Destroy the service and clean up all resources.
105
+ */
106
+ destroy(): void;
107
+ }
108
+ export {};
109
+ //# sourceMappingURL=OHLCVService.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OHLCVService.d.mts","sourceRoot":"","sources":["../../../src/ws/ohlcv/OHLCVService.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,aAAa,EAGd,mCAAmC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAIrD,OAAO,KAAK,EAEV,kDAAkD,EAEnD,uCAAmC;AAEpC,OAAO,KAAK,EAAE,oCAAoC,EAAE,2DAAuD;AAC3G,OAAO,KAAK,EAAE,yBAAyB,EAAE,+CAA2C;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,wBAAwB,EAAE,oBAAgB;AAMlE,QAAA,MAAM,YAAY,iBAAiB,CAAC;AA0BpC;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAMF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,kFAAkF;IAClF,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB,CAAC;AAMF,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;AAE5D,eAAO,MAAM,6BAA6B,+aAUhC,CAAC;AAEX,eAAO,MAAM,4BAA4B,6DAE/B,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,oCAAoC,CAAC;AAIlE,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,CAAC;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,gCAAgC,CAAC;IACvC,OAAO,EAAE,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B,2BAA2B,GAC3B,mCAAmC,GACnC,kCAAkC,CAAC;AAEvC,MAAM,MAAM,aAAa,GAAG,kDAAkD,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,YAAY,EACnB,mBAAmB,GAAG,cAAc,EACpC,kBAAkB,GAAG,aAAa,CACnC,CAAC;AAMF;;;;;;;;;;;;GAYG;AACH,qBAAa,YAAY;;IACvB,QAAQ,CAAC,IAAI,kBAAgB;gBAiB3B,OAAO,EAAE,mBAAmB,GAAG;QAAE,SAAS,EAAE,qBAAqB,CAAA;KAAE;IAwBrE;;OAEG;IACH,IAAI,IAAI,IAAI;IAaZ;;;;;;;;OAQG;IACG,SAAS,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiFjE;;;;;;;OAOG;IACG,WAAW,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiOnE;;OAEG;IACH,OAAO,IAAI,IAAI;CAchB"}
@@ -0,0 +1,355 @@
1
+ /**
2
+ * OHLCV Service for real-time candlestick data streaming via WebSocket.
3
+ *
4
+ * Wraps {@link BackendWebSocketService} through the messenger pattern to
5
+ * provide subscribe/unsubscribe semantics for OHLCV market-data channels.
6
+ * Includes reference counting, grace-period unsubscribe, idempotency checks,
7
+ * chain-status forwarding, and automatic resubscription on reconnect.
8
+ */
9
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
10
+ if (kind === "m") throw new TypeError("Private method is not writable");
11
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
12
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
13
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
14
+ };
15
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
16
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
17
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
18
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
19
+ };
20
+ var _OHLCVService_instances, _OHLCVService_messenger, _OHLCVService_trace, _OHLCVService_channels, _OHLCVService_mutex, _OHLCVService_chainsUp, _OHLCVService_subscribeInner, _OHLCVService_unsubscribeInner, _OHLCVService_performUnsubscribe, _OHLCVService_resubscribeActiveChannels, _OHLCVService_handleBarUpdate, _OHLCVService_handleSystemNotification, _OHLCVService_handleWebSocketStateChange, _OHLCVService_buildChannel;
21
+ import { Mutex } from "async-mutex";
22
+ import { projectLogger, createModuleLogger } from "../../logger.mjs";
23
+ import { WebSocketState } from "../BackendWebSocketService.mjs";
24
+ // =============================================================================
25
+ // Constants
26
+ // =============================================================================
27
+ const SERVICE_NAME = 'OHLCVService';
28
+ const log = createModuleLogger(projectLogger, SERVICE_NAME);
29
+ const MESSENGER_EXPOSED_METHODS = ['subscribe', 'unsubscribe'];
30
+ const SUBSCRIPTION_NAMESPACE = 'market-data.v1';
31
+ const SYSTEM_NOTIFICATIONS_CHANNEL = `system-notifications.v1.${SUBSCRIPTION_NAMESPACE}`;
32
+ /** Delay before actually unsubscribing from a channel after refCount reaches 0. */
33
+ const GRACE_PERIOD_MS = 3000;
34
+ export const OHLCV_SERVICE_ALLOWED_ACTIONS = [
35
+ 'BackendWebSocketService:connect',
36
+ 'BackendWebSocketService:forceReconnection',
37
+ 'BackendWebSocketService:subscribe',
38
+ 'BackendWebSocketService:getConnectionInfo',
39
+ 'BackendWebSocketService:channelHasSubscription',
40
+ 'BackendWebSocketService:getSubscriptionsByChannel',
41
+ 'BackendWebSocketService:findSubscriptionsByChannelPrefix',
42
+ 'BackendWebSocketService:addChannelCallback',
43
+ 'BackendWebSocketService:removeChannelCallback',
44
+ ];
45
+ export const OHLCV_SERVICE_ALLOWED_EVENTS = [
46
+ 'BackendWebSocketService:connectionStateChanged',
47
+ ];
48
+ // =============================================================================
49
+ // Main Service Class
50
+ // =============================================================================
51
+ /**
52
+ * Service for real-time OHLCV candlestick streaming via the backend WebSocket
53
+ * gateway. Communicates with {@link BackendWebSocketService} exclusively
54
+ * through the messenger — no direct import of the class.
55
+ *
56
+ * Features:
57
+ * - Reference counting: multiple UI consumers share one WebSocket subscription
58
+ * - Grace-period unsubscribe: avoids rapid unsub/resub during navigation
59
+ * - Idempotency: duplicate subscribe calls for the same channel are no-ops
60
+ * - Reconnect resilience: resubscribes all active channels on reconnect
61
+ * - Chain-status forwarding: listens to system-notifications for chain up/down
62
+ *
63
+ */
64
+ export class OHLCVService {
65
+ // =============================================================================
66
+ // Constructor
67
+ // =============================================================================
68
+ constructor(options) {
69
+ _OHLCVService_instances.add(this);
70
+ this.name = SERVICE_NAME;
71
+ _OHLCVService_messenger.set(this, void 0);
72
+ _OHLCVService_trace.set(this, void 0);
73
+ _OHLCVService_channels.set(this, new Map());
74
+ _OHLCVService_mutex.set(this, new Mutex());
75
+ _OHLCVService_chainsUp.set(this, new Set());
76
+ __classPrivateFieldSet(this, _OHLCVService_messenger, options.messenger, "f");
77
+ __classPrivateFieldSet(this, _OHLCVService_trace, options.traceFn ??
78
+ ((_request, fn) => fn?.()), "f");
79
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
80
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").subscribe('BackendWebSocketService:connectionStateChanged',
81
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
82
+ (connectionInfo) => __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_handleWebSocketStateChange).call(this, connectionInfo));
83
+ }
84
+ /**
85
+ * Register the system-notifications channel callback.
86
+ */
87
+ init() {
88
+ log('OHLCV-WS: Initializing — registering system-notifications callback');
89
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:addChannelCallback', {
90
+ channelName: SYSTEM_NOTIFICATIONS_CHANNEL,
91
+ callback: (notification) => __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_handleSystemNotification).call(this, notification),
92
+ });
93
+ }
94
+ // =============================================================================
95
+ // Public — Subscribe / Unsubscribe
96
+ // =============================================================================
97
+ /**
98
+ * Subscribe to an OHLCV channel. If this is the first subscriber for the
99
+ * given asset/interval/currency combination a WebSocket subscription is
100
+ * created. Additional calls for the same combination only bump the reference
101
+ * count.
102
+ *
103
+ * @param options - The subscription parameters.
104
+ * @returns A promise that resolves once the subscription is established.
105
+ */
106
+ async subscribe(options) {
107
+ const channel = __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_buildChannel).call(this, options);
108
+ const releaseLock = await __classPrivateFieldGet(this, _OHLCVService_mutex, "f").acquire();
109
+ try {
110
+ await __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_subscribeInner).call(this, channel);
111
+ }
112
+ finally {
113
+ releaseLock();
114
+ }
115
+ }
116
+ /**
117
+ * Unsubscribe from an OHLCV channel. Decrements the reference count and,
118
+ * when it reaches zero, starts a grace-period timer before actually
119
+ * unsubscribing from the WebSocket to absorb rapid navigation patterns.
120
+ *
121
+ * @param options - The subscription parameters to unsubscribe from.
122
+ * @returns A promise that resolves once the unsubscription is processed.
123
+ */
124
+ async unsubscribe(options) {
125
+ const channel = __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_buildChannel).call(this, options);
126
+ const releaseLock = await __classPrivateFieldGet(this, _OHLCVService_mutex, "f").acquire();
127
+ try {
128
+ await __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_unsubscribeInner).call(this, channel);
129
+ }
130
+ finally {
131
+ releaseLock();
132
+ }
133
+ }
134
+ // =============================================================================
135
+ // Public — Cleanup
136
+ // =============================================================================
137
+ /**
138
+ * Destroy the service and clean up all resources.
139
+ */
140
+ destroy() {
141
+ for (const entry of __classPrivateFieldGet(this, _OHLCVService_channels, "f").values()) {
142
+ if (entry.gracePeriodTimer) {
143
+ clearTimeout(entry.gracePeriodTimer);
144
+ }
145
+ }
146
+ __classPrivateFieldGet(this, _OHLCVService_channels, "f").clear();
147
+ __classPrivateFieldGet(this, _OHLCVService_chainsUp, "f").clear();
148
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:removeChannelCallback', SYSTEM_NOTIFICATIONS_CHANNEL);
149
+ }
150
+ }
151
+ _OHLCVService_messenger = new WeakMap(), _OHLCVService_trace = new WeakMap(), _OHLCVService_channels = new WeakMap(), _OHLCVService_mutex = new WeakMap(), _OHLCVService_chainsUp = new WeakMap(), _OHLCVService_instances = new WeakSet(), _OHLCVService_subscribeInner = async function _OHLCVService_subscribeInner(channel) {
152
+ const entry = __classPrivateFieldGet(this, _OHLCVService_channels, "f").get(channel);
153
+ if (entry?.gracePeriodTimer) {
154
+ clearTimeout(entry.gracePeriodTimer);
155
+ entry.gracePeriodTimer = undefined;
156
+ log('OHLCV-WS: Cancelled grace-period unsubscribe', {
157
+ channel,
158
+ });
159
+ if (__classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:channelHasSubscription', channel)) {
160
+ entry.refCount += 1;
161
+ log('OHLCV-WS: WS subscription still alive, bumped refCount', {
162
+ channel,
163
+ refCount: entry.refCount,
164
+ });
165
+ return;
166
+ }
167
+ // WS subscription was lost (e.g. after disconnect/reconnect) — fall
168
+ // through to recreate it. refCount is bumped only after success below.
169
+ }
170
+ else if (entry && entry.refCount > 0) {
171
+ entry.refCount += 1;
172
+ return;
173
+ }
174
+ try {
175
+ await __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:connect');
176
+ if (__classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:channelHasSubscription', channel)) {
177
+ log('OHLCV-WS: Channel already has WS subscription (idempotency), skipping', {
178
+ channel,
179
+ });
180
+ __classPrivateFieldGet(this, _OHLCVService_channels, "f").set(channel, { refCount: 1 });
181
+ return;
182
+ }
183
+ await __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:subscribe', {
184
+ channels: [channel],
185
+ channelType: SUBSCRIPTION_NAMESPACE,
186
+ callback: (notification) => {
187
+ __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_handleBarUpdate).call(this, channel, notification);
188
+ },
189
+ });
190
+ __classPrivateFieldGet(this, _OHLCVService_channels, "f").set(channel, { refCount: 1 });
191
+ log('OHLCV-WS: Subscribe succeeded — new WS subscription created', {
192
+ channel,
193
+ });
194
+ }
195
+ catch (error) {
196
+ log('OHLCV-WS: Subscription failed', { channel, error });
197
+ __classPrivateFieldGet(this, _OHLCVService_channels, "f").delete(channel);
198
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").publish('OHLCVService:subscriptionError', {
199
+ channel,
200
+ error: String(error),
201
+ operation: 'subscribe',
202
+ });
203
+ }
204
+ }, _OHLCVService_unsubscribeInner = async function _OHLCVService_unsubscribeInner(channel) {
205
+ const entry = __classPrivateFieldGet(this, _OHLCVService_channels, "f").get(channel);
206
+ if (!entry || entry.refCount <= 0) {
207
+ return;
208
+ }
209
+ entry.refCount -= 1;
210
+ if (entry.refCount > 0) {
211
+ return;
212
+ }
213
+ entry.gracePeriodTimer = setTimeout(() => {
214
+ entry.gracePeriodTimer = undefined;
215
+ __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_performUnsubscribe).call(this, channel).catch(() => {
216
+ // no-op
217
+ });
218
+ }, GRACE_PERIOD_MS);
219
+ }, _OHLCVService_performUnsubscribe =
220
+ // =============================================================================
221
+ // Private — WebSocket Subscription Helpers
222
+ // =============================================================================
223
+ async function _OHLCVService_performUnsubscribe(channel) {
224
+ const releaseLock = await __classPrivateFieldGet(this, _OHLCVService_mutex, "f").acquire();
225
+ try {
226
+ const entry = __classPrivateFieldGet(this, _OHLCVService_channels, "f").get(channel);
227
+ if (entry && entry.refCount > 0) {
228
+ log('OHLCV-WS: Skipping unsubscribe — new subscriber arrived while queued', { channel, refCount: entry.refCount });
229
+ return;
230
+ }
231
+ log('OHLCV-WS: Grace period expired — performing actual WS unsubscribe', {
232
+ channel,
233
+ });
234
+ __classPrivateFieldGet(this, _OHLCVService_channels, "f").delete(channel);
235
+ try {
236
+ const subscriptions = __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:getSubscriptionsByChannel', channel);
237
+ for (const sub of subscriptions) {
238
+ await sub.unsubscribe();
239
+ }
240
+ log('OHLCV-WS: WS unsubscribe completed', { channel });
241
+ }
242
+ catch (error) {
243
+ log('OHLCV-WS: Unsubscription failed', { channel, error });
244
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").publish('OHLCVService:subscriptionError', {
245
+ channel,
246
+ error: String(error),
247
+ operation: 'unsubscribe',
248
+ });
249
+ }
250
+ }
251
+ finally {
252
+ releaseLock();
253
+ }
254
+ }, _OHLCVService_resubscribeActiveChannels =
255
+ /**
256
+ * Resubscribe all channels that were active before a disconnect.
257
+ * Called when WebSocket transitions to CONNECTED.
258
+ */
259
+ async function _OHLCVService_resubscribeActiveChannels() {
260
+ const releaseLock = await __classPrivateFieldGet(this, _OHLCVService_mutex, "f").acquire();
261
+ try {
262
+ const channelCount = __classPrivateFieldGet(this, _OHLCVService_channels, "f").size;
263
+ log('OHLCV-WS: Resubscribing active channels after reconnect', {
264
+ count: channelCount,
265
+ });
266
+ for (const [channel, entry] of __classPrivateFieldGet(this, _OHLCVService_channels, "f").entries()) {
267
+ if (entry.refCount === 0) {
268
+ continue;
269
+ }
270
+ try {
271
+ if (__classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:channelHasSubscription', channel)) {
272
+ log('OHLCV-WS: Channel already subscribed on server, skipping resubscribe', {
273
+ channel,
274
+ });
275
+ continue;
276
+ }
277
+ await __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:subscribe', {
278
+ channels: [channel],
279
+ channelType: SUBSCRIPTION_NAMESPACE,
280
+ callback: (notification) => {
281
+ __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_handleBarUpdate).call(this, channel, notification);
282
+ },
283
+ });
284
+ log('OHLCV-WS: Resubscription succeeded', { channel });
285
+ }
286
+ catch (error) {
287
+ log('OHLCV-WS: Resubscription failed for channel', {
288
+ channel,
289
+ error,
290
+ });
291
+ }
292
+ }
293
+ }
294
+ finally {
295
+ releaseLock();
296
+ }
297
+ }, _OHLCVService_handleBarUpdate = function _OHLCVService_handleBarUpdate(channel, notification) {
298
+ const bar = notification.data;
299
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
300
+ __classPrivateFieldGet(this, _OHLCVService_trace, "f").call(this, {
301
+ name: `${SERVICE_NAME} Bar Update`,
302
+ data: { channel, timestamp: bar.timestamp },
303
+ tags: { service: SERVICE_NAME },
304
+ }, () => {
305
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").publish('OHLCVService:barUpdated', { channel, bar });
306
+ });
307
+ }, _OHLCVService_handleSystemNotification = function _OHLCVService_handleSystemNotification(notification) {
308
+ const data = notification.data;
309
+ const { timestamp } = notification;
310
+ if (!data.chainIds || !Array.isArray(data.chainIds) || !data.status) {
311
+ throw new Error('Invalid system notification data: missing chainIds or status');
312
+ }
313
+ if (data.status === 'up') {
314
+ for (const chainId of data.chainIds) {
315
+ __classPrivateFieldGet(this, _OHLCVService_chainsUp, "f").add(chainId);
316
+ }
317
+ }
318
+ else {
319
+ for (const chainId of data.chainIds) {
320
+ __classPrivateFieldGet(this, _OHLCVService_chainsUp, "f").delete(chainId);
321
+ }
322
+ }
323
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").publish('OHLCVService:chainStatusChanged', {
324
+ chainIds: data.chainIds,
325
+ status: data.status,
326
+ timestamp,
327
+ });
328
+ log(`OHLCV-WS: Chain status change: ${data.status}`, {
329
+ chains: data.chainIds,
330
+ status: data.status,
331
+ });
332
+ }, _OHLCVService_handleWebSocketStateChange = async function _OHLCVService_handleWebSocketStateChange(connectionInfo) {
333
+ const { state } = connectionInfo;
334
+ if (state === WebSocketState.CONNECTED) {
335
+ await __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_resubscribeActiveChannels).call(this);
336
+ }
337
+ else if (state === WebSocketState.DISCONNECTED) {
338
+ const chainsToMarkDown = Array.from(__classPrivateFieldGet(this, _OHLCVService_chainsUp, "f"));
339
+ if (chainsToMarkDown.length > 0) {
340
+ __classPrivateFieldGet(this, _OHLCVService_messenger, "f").publish('OHLCVService:chainStatusChanged', {
341
+ chainIds: chainsToMarkDown,
342
+ status: 'down',
343
+ timestamp: Date.now(),
344
+ });
345
+ log('OHLCV-WS: WebSocket disconnection — marked tracked chains as down', {
346
+ count: chainsToMarkDown.length,
347
+ chains: chainsToMarkDown,
348
+ });
349
+ __classPrivateFieldGet(this, _OHLCVService_chainsUp, "f").clear();
350
+ }
351
+ }
352
+ }, _OHLCVService_buildChannel = function _OHLCVService_buildChannel(options) {
353
+ return `${SUBSCRIPTION_NAMESPACE}.${options.assetId}.${options.interval}.${options.currency}`;
354
+ };
355
+ //# sourceMappingURL=OHLCVService.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OHLCVService.mjs","sourceRoot":"","sources":["../../../src/ws/ohlcv/OHLCVService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OHLCV Service for real-time candlestick data streaming via WebSocket.\n *\n * Wraps {@link BackendWebSocketService} through the messenger pattern to\n * provide subscribe/unsubscribe semantics for OHLCV market-data channels.\n * Includes reference counting, grace-period unsubscribe, idempotency checks,\n * chain-status forwarding, and automatic resubscription on reconnect.\n */\n\nimport type {\n TraceCallback,\n TraceContext,\n TraceRequest,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport { Mutex } from 'async-mutex';\n\nimport { projectLogger, createModuleLogger } from '../../logger';\nimport type {\n WebSocketConnectionInfo,\n BackendWebSocketServiceConnectionStateChangedEvent,\n ServerNotificationMessage,\n} from '../BackendWebSocketService';\nimport { WebSocketState } from '../BackendWebSocketService';\nimport type { BackendWebSocketServiceMethodActions } from '../BackendWebSocketService-method-action-types';\nimport type { OHLCVServiceMethodActions } from './OHLCVService-method-action-types';\nimport type { OHLCVBar, OHLCVSubscriptionOptions } from './types';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst SERVICE_NAME = 'OHLCVService';\n\nconst log = createModuleLogger(projectLogger, SERVICE_NAME);\n\nconst MESSENGER_EXPOSED_METHODS = ['subscribe', 'unsubscribe'] as const;\n\nconst SUBSCRIPTION_NAMESPACE = 'market-data.v1';\n\nconst SYSTEM_NOTIFICATIONS_CHANNEL = `system-notifications.v1.${SUBSCRIPTION_NAMESPACE}`;\n\n/** Delay before actually unsubscribing from a channel after refCount reaches 0. */\nconst GRACE_PERIOD_MS = 3_000;\n\n// =============================================================================\n// Types — Channel Tracking\n// =============================================================================\n\ntype ChannelEntry = {\n refCount: number;\n gracePeriodTimer?: ReturnType<typeof setTimeout>;\n};\n\n// =============================================================================\n// Types — System Notifications\n// =============================================================================\n\n/**\n * System notification data for chain status updates on market-data channels.\n */\nexport type OHLCVSystemNotificationData = {\n chainIds: string[];\n status: 'down' | 'up';\n timestamp?: number;\n};\n\n// =============================================================================\n// Types — Service Options\n// =============================================================================\n\n/**\n * Configuration options for the OHLCV service.\n */\nexport type OHLCVServiceOptions = {\n /** Optional callback to trace performance of OHLCV operations (default: no-op) */\n traceFn?: TraceCallback;\n};\n\n// =============================================================================\n// Action and Event Types\n// =============================================================================\n\nexport type OHLCVServiceActions = OHLCVServiceMethodActions;\n\nexport const OHLCV_SERVICE_ALLOWED_ACTIONS = [\n 'BackendWebSocketService:connect',\n 'BackendWebSocketService:forceReconnection',\n 'BackendWebSocketService:subscribe',\n 'BackendWebSocketService:getConnectionInfo',\n 'BackendWebSocketService:channelHasSubscription',\n 'BackendWebSocketService:getSubscriptionsByChannel',\n 'BackendWebSocketService:findSubscriptionsByChannelPrefix',\n 'BackendWebSocketService:addChannelCallback',\n 'BackendWebSocketService:removeChannelCallback',\n] as const;\n\nexport const OHLCV_SERVICE_ALLOWED_EVENTS = [\n 'BackendWebSocketService:connectionStateChanged',\n] as const;\n\nexport type AllowedActions = BackendWebSocketServiceMethodActions;\n\n// Events published by OHLCVService\n\nexport type OHLCVServiceBarUpdatedEvent = {\n type: `OHLCVService:barUpdated`;\n payload: [{ channel: string; bar: OHLCVBar }];\n};\n\nexport type OHLCVServiceChainStatusChangedEvent = {\n type: `OHLCVService:chainStatusChanged`;\n payload: [{ chainIds: string[]; status: 'up' | 'down'; timestamp?: number }];\n};\n\nexport type OHLCVServiceSubscriptionErrorEvent = {\n type: `OHLCVService:subscriptionError`;\n payload: [{ channel: string; error: string; operation: string }];\n};\n\nexport type OHLCVServiceEvents =\n | OHLCVServiceBarUpdatedEvent\n | OHLCVServiceChainStatusChangedEvent\n | OHLCVServiceSubscriptionErrorEvent;\n\nexport type AllowedEvents = BackendWebSocketServiceConnectionStateChangedEvent;\n\nexport type OHLCVServiceMessenger = Messenger<\n typeof SERVICE_NAME,\n OHLCVServiceActions | AllowedActions,\n OHLCVServiceEvents | AllowedEvents\n>;\n\n// =============================================================================\n// Main Service Class\n// =============================================================================\n\n/**\n * Service for real-time OHLCV candlestick streaming via the backend WebSocket\n * gateway. Communicates with {@link BackendWebSocketService} exclusively\n * through the messenger — no direct import of the class.\n *\n * Features:\n * - Reference counting: multiple UI consumers share one WebSocket subscription\n * - Grace-period unsubscribe: avoids rapid unsub/resub during navigation\n * - Idempotency: duplicate subscribe calls for the same channel are no-ops\n * - Reconnect resilience: resubscribes all active channels on reconnect\n * - Chain-status forwarding: listens to system-notifications for chain up/down\n *\n */\nexport class OHLCVService {\n readonly name = SERVICE_NAME;\n\n readonly #messenger: OHLCVServiceMessenger;\n\n readonly #trace: TraceCallback;\n\n readonly #channels = new Map<string, ChannelEntry>();\n\n readonly #mutex = new Mutex();\n\n readonly #chainsUp = new Set<string>();\n\n // =============================================================================\n // Constructor\n // =============================================================================\n\n constructor(\n options: OHLCVServiceOptions & { messenger: OHLCVServiceMessenger },\n ) {\n this.#messenger = options.messenger;\n\n this.#trace =\n options.traceFn ??\n ((<Result>(\n _request: TraceRequest,\n fn?: (context?: TraceContext) => Result,\n ) => fn?.()) as TraceCallback);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n this.#messenger.subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n (connectionInfo: WebSocketConnectionInfo) =>\n this.#handleWebSocketStateChange(connectionInfo),\n );\n }\n\n /**\n * Register the system-notifications channel callback.\n */\n init(): void {\n log('OHLCV-WS: Initializing — registering system-notifications callback');\n this.#messenger.call('BackendWebSocketService:addChannelCallback', {\n channelName: SYSTEM_NOTIFICATIONS_CHANNEL,\n callback: (notification: ServerNotificationMessage) =>\n this.#handleSystemNotification(notification),\n });\n }\n\n // =============================================================================\n // Public — Subscribe / Unsubscribe\n // =============================================================================\n\n /**\n * Subscribe to an OHLCV channel. If this is the first subscriber for the\n * given asset/interval/currency combination a WebSocket subscription is\n * created. Additional calls for the same combination only bump the reference\n * count.\n *\n * @param options - The subscription parameters.\n * @returns A promise that resolves once the subscription is established.\n */\n async subscribe(options: OHLCVSubscriptionOptions): Promise<void> {\n const channel = this.#buildChannel(options);\n const releaseLock = await this.#mutex.acquire();\n try {\n await this.#subscribeInner(channel);\n } finally {\n releaseLock();\n }\n }\n\n async #subscribeInner(channel: string): Promise<void> {\n const entry = this.#channels.get(channel);\n\n if (entry?.gracePeriodTimer) {\n clearTimeout(entry.gracePeriodTimer);\n entry.gracePeriodTimer = undefined;\n log('OHLCV-WS: Cancelled grace-period unsubscribe', {\n channel,\n });\n\n if (\n this.#messenger.call(\n 'BackendWebSocketService:channelHasSubscription',\n channel,\n )\n ) {\n entry.refCount += 1;\n log('OHLCV-WS: WS subscription still alive, bumped refCount', {\n channel,\n refCount: entry.refCount,\n });\n return;\n }\n // WS subscription was lost (e.g. after disconnect/reconnect) — fall\n // through to recreate it. refCount is bumped only after success below.\n } else if (entry && entry.refCount > 0) {\n entry.refCount += 1;\n return;\n }\n try {\n await this.#messenger.call('BackendWebSocketService:connect');\n\n if (\n this.#messenger.call(\n 'BackendWebSocketService:channelHasSubscription',\n channel,\n )\n ) {\n log(\n 'OHLCV-WS: Channel already has WS subscription (idempotency), skipping',\n {\n channel,\n },\n );\n this.#channels.set(channel, { refCount: 1 });\n return;\n }\n\n await this.#messenger.call('BackendWebSocketService:subscribe', {\n channels: [channel],\n channelType: SUBSCRIPTION_NAMESPACE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleBarUpdate(channel, notification);\n },\n });\n\n this.#channels.set(channel, { refCount: 1 });\n log('OHLCV-WS: Subscribe succeeded — new WS subscription created', {\n channel,\n });\n } catch (error) {\n log('OHLCV-WS: Subscription failed', { channel, error });\n this.#channels.delete(channel);\n this.#messenger.publish('OHLCVService:subscriptionError', {\n channel,\n error: String(error),\n operation: 'subscribe',\n });\n }\n }\n\n /**\n * Unsubscribe from an OHLCV channel. Decrements the reference count and,\n * when it reaches zero, starts a grace-period timer before actually\n * unsubscribing from the WebSocket to absorb rapid navigation patterns.\n *\n * @param options - The subscription parameters to unsubscribe from.\n * @returns A promise that resolves once the unsubscription is processed.\n */\n async unsubscribe(options: OHLCVSubscriptionOptions): Promise<void> {\n const channel = this.#buildChannel(options);\n const releaseLock = await this.#mutex.acquire();\n try {\n await this.#unsubscribeInner(channel);\n } finally {\n releaseLock();\n }\n }\n\n async #unsubscribeInner(channel: string): Promise<void> {\n const entry = this.#channels.get(channel);\n\n if (!entry || entry.refCount <= 0) {\n return;\n }\n\n entry.refCount -= 1;\n\n if (entry.refCount > 0) {\n return;\n }\n\n entry.gracePeriodTimer = setTimeout(() => {\n entry.gracePeriodTimer = undefined;\n this.#performUnsubscribe(channel).catch(() => {\n // no-op\n });\n }, GRACE_PERIOD_MS);\n }\n\n // =============================================================================\n // Private — WebSocket Subscription Helpers\n // =============================================================================\n\n async #performUnsubscribe(channel: string): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n try {\n const entry = this.#channels.get(channel);\n if (entry && entry.refCount > 0) {\n log(\n 'OHLCV-WS: Skipping unsubscribe — new subscriber arrived while queued',\n { channel, refCount: entry.refCount },\n );\n return;\n }\n\n log('OHLCV-WS: Grace period expired — performing actual WS unsubscribe', {\n channel,\n });\n this.#channels.delete(channel);\n\n try {\n const subscriptions = this.#messenger.call(\n 'BackendWebSocketService:getSubscriptionsByChannel',\n channel,\n );\n\n for (const sub of subscriptions) {\n await sub.unsubscribe();\n }\n log('OHLCV-WS: WS unsubscribe completed', { channel });\n } catch (error) {\n log('OHLCV-WS: Unsubscription failed', { channel, error });\n this.#messenger.publish('OHLCVService:subscriptionError', {\n channel,\n error: String(error),\n operation: 'unsubscribe',\n });\n }\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Resubscribe all channels that were active before a disconnect.\n * Called when WebSocket transitions to CONNECTED.\n */\n async #resubscribeActiveChannels(): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n try {\n const channelCount = this.#channels.size;\n log('OHLCV-WS: Resubscribing active channels after reconnect', {\n count: channelCount,\n });\n\n for (const [channel, entry] of this.#channels.entries()) {\n if (entry.refCount === 0) {\n continue;\n }\n\n try {\n if (\n this.#messenger.call(\n 'BackendWebSocketService:channelHasSubscription',\n channel,\n )\n ) {\n log(\n 'OHLCV-WS: Channel already subscribed on server, skipping resubscribe',\n {\n channel,\n },\n );\n continue;\n }\n\n await this.#messenger.call('BackendWebSocketService:subscribe', {\n channels: [channel],\n channelType: SUBSCRIPTION_NAMESPACE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleBarUpdate(channel, notification);\n },\n });\n log('OHLCV-WS: Resubscription succeeded', { channel });\n } catch (error) {\n log('OHLCV-WS: Resubscription failed for channel', {\n channel,\n error,\n });\n }\n }\n } finally {\n releaseLock();\n }\n }\n\n // =============================================================================\n // Private — Message Handlers\n // =============================================================================\n\n #handleBarUpdate(\n channel: string,\n notification: ServerNotificationMessage,\n ): void {\n const bar = notification.data as OHLCVBar;\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#trace(\n {\n name: `${SERVICE_NAME} Bar Update`,\n data: { channel, timestamp: bar.timestamp },\n tags: { service: SERVICE_NAME },\n },\n () => {\n this.#messenger.publish('OHLCVService:barUpdated', { channel, bar });\n },\n );\n }\n\n #handleSystemNotification(notification: ServerNotificationMessage): void {\n const data = notification.data as OHLCVSystemNotificationData;\n const { timestamp } = notification;\n\n if (!data.chainIds || !Array.isArray(data.chainIds) || !data.status) {\n throw new Error(\n 'Invalid system notification data: missing chainIds or status',\n );\n }\n\n if (data.status === 'up') {\n for (const chainId of data.chainIds) {\n this.#chainsUp.add(chainId);\n }\n } else {\n for (const chainId of data.chainIds) {\n this.#chainsUp.delete(chainId);\n }\n }\n\n this.#messenger.publish('OHLCVService:chainStatusChanged', {\n chainIds: data.chainIds,\n status: data.status,\n timestamp,\n });\n\n log(`OHLCV-WS: Chain status change: ${data.status}`, {\n chains: data.chainIds,\n status: data.status,\n });\n }\n\n async #handleWebSocketStateChange(\n connectionInfo: WebSocketConnectionInfo,\n ): Promise<void> {\n const { state } = connectionInfo;\n\n if (state === WebSocketState.CONNECTED) {\n await this.#resubscribeActiveChannels();\n } else if (state === WebSocketState.DISCONNECTED) {\n const chainsToMarkDown = Array.from(this.#chainsUp);\n\n if (chainsToMarkDown.length > 0) {\n this.#messenger.publish('OHLCVService:chainStatusChanged', {\n chainIds: chainsToMarkDown,\n status: 'down',\n timestamp: Date.now(),\n });\n\n log(\n 'OHLCV-WS: WebSocket disconnection — marked tracked chains as down',\n {\n count: chainsToMarkDown.length,\n chains: chainsToMarkDown,\n },\n );\n\n this.#chainsUp.clear();\n }\n }\n }\n\n // =============================================================================\n // Private — Utility\n // =============================================================================\n\n #buildChannel(options: OHLCVSubscriptionOptions): string {\n return `${SUBSCRIPTION_NAMESPACE}.${options.assetId}.${options.interval}.${options.currency}`;\n }\n\n // =============================================================================\n // Public — Cleanup\n // =============================================================================\n\n /**\n * Destroy the service and clean up all resources.\n */\n destroy(): void {\n for (const entry of this.#channels.values()) {\n if (entry.gracePeriodTimer) {\n clearTimeout(entry.gracePeriodTimer);\n }\n }\n this.#channels.clear();\n this.#chainsUp.clear();\n\n this.#messenger.call(\n 'BackendWebSocketService:removeChannelCallback',\n SYSTEM_NOTIFICATIONS_CHANNEL,\n );\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OHLCV_SERVICE_ALLOWED_EVENTS = exports.OHLCV_SERVICE_ALLOWED_ACTIONS = exports.OHLCVService = void 0;
4
+ var OHLCVService_1 = require("./OHLCVService.cjs");
5
+ Object.defineProperty(exports, "OHLCVService", { enumerable: true, get: function () { return OHLCVService_1.OHLCVService; } });
6
+ var OHLCVService_2 = require("./OHLCVService.cjs");
7
+ Object.defineProperty(exports, "OHLCV_SERVICE_ALLOWED_ACTIONS", { enumerable: true, get: function () { return OHLCVService_2.OHLCV_SERVICE_ALLOWED_ACTIONS; } });
8
+ Object.defineProperty(exports, "OHLCV_SERVICE_ALLOWED_EVENTS", { enumerable: true, get: function () { return OHLCVService_2.OHLCV_SERVICE_ALLOWED_EVENTS; } });
9
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../../src/ws/ohlcv/index.ts"],"names":[],"mappings":";;;AAAA,mDAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,mDAGwB;AAFtB,6HAAA,6BAA6B,OAAA;AAC7B,4HAAA,4BAA4B,OAAA","sourcesContent":["export { OHLCVService } from './OHLCVService';\nexport {\n OHLCV_SERVICE_ALLOWED_ACTIONS,\n OHLCV_SERVICE_ALLOWED_EVENTS,\n} from './OHLCVService';\nexport type {\n OHLCVSystemNotificationData,\n OHLCVServiceOptions,\n OHLCVServiceActions,\n AllowedActions as OHLCVServiceAllowedActions,\n OHLCVServiceBarUpdatedEvent,\n OHLCVServiceChainStatusChangedEvent,\n OHLCVServiceSubscriptionErrorEvent,\n OHLCVServiceEvents,\n AllowedEvents as OHLCVServiceAllowedEvents,\n OHLCVServiceMessenger,\n} from './OHLCVService';\nexport type { OHLCVBar, OHLCVSubscriptionOptions } from './types';\n"]}
@@ -0,0 +1,5 @@
1
+ export { OHLCVService } from "./OHLCVService.cjs";
2
+ export { OHLCV_SERVICE_ALLOWED_ACTIONS, OHLCV_SERVICE_ALLOWED_EVENTS, } from "./OHLCVService.cjs";
3
+ export type { OHLCVSystemNotificationData, OHLCVServiceOptions, OHLCVServiceActions, AllowedActions as OHLCVServiceAllowedActions, OHLCVServiceBarUpdatedEvent, OHLCVServiceChainStatusChangedEvent, OHLCVServiceSubscriptionErrorEvent, OHLCVServiceEvents, AllowedEvents as OHLCVServiceAllowedEvents, OHLCVServiceMessenger, } from "./OHLCVService.cjs";
4
+ export type { OHLCVBar, OHLCVSubscriptionOptions } from "./types.cjs";
5
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/ws/ohlcv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,2BAAuB;AAC9C,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,GAC7B,2BAAuB;AACxB,YAAY,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,IAAI,0BAA0B,EAC5C,2BAA2B,EAC3B,mCAAmC,EACnC,kCAAkC,EAClC,kBAAkB,EAClB,aAAa,IAAI,yBAAyB,EAC1C,qBAAqB,GACtB,2BAAuB;AACxB,YAAY,EAAE,QAAQ,EAAE,wBAAwB,EAAE,oBAAgB"}
@@ -0,0 +1,5 @@
1
+ export { OHLCVService } from "./OHLCVService.mjs";
2
+ export { OHLCV_SERVICE_ALLOWED_ACTIONS, OHLCV_SERVICE_ALLOWED_EVENTS, } from "./OHLCVService.mjs";
3
+ export type { OHLCVSystemNotificationData, OHLCVServiceOptions, OHLCVServiceActions, AllowedActions as OHLCVServiceAllowedActions, OHLCVServiceBarUpdatedEvent, OHLCVServiceChainStatusChangedEvent, OHLCVServiceSubscriptionErrorEvent, OHLCVServiceEvents, AllowedEvents as OHLCVServiceAllowedEvents, OHLCVServiceMessenger, } from "./OHLCVService.mjs";
4
+ export type { OHLCVBar, OHLCVSubscriptionOptions } from "./types.mjs";
5
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/ws/ohlcv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,2BAAuB;AAC9C,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,GAC7B,2BAAuB;AACxB,YAAY,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,IAAI,0BAA0B,EAC5C,2BAA2B,EAC3B,mCAAmC,EACnC,kCAAkC,EAClC,kBAAkB,EAClB,aAAa,IAAI,yBAAyB,EAC1C,qBAAqB,GACtB,2BAAuB;AACxB,YAAY,EAAE,QAAQ,EAAE,wBAAwB,EAAE,oBAAgB"}
@@ -0,0 +1,3 @@
1
+ export { OHLCVService } from "./OHLCVService.mjs";
2
+ export { OHLCV_SERVICE_ALLOWED_ACTIONS, OHLCV_SERVICE_ALLOWED_EVENTS } from "./OHLCVService.mjs";
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../src/ws/ohlcv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,2BAAuB;AAC9C,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC7B,2BAAuB","sourcesContent":["export { OHLCVService } from './OHLCVService';\nexport {\n OHLCV_SERVICE_ALLOWED_ACTIONS,\n OHLCV_SERVICE_ALLOWED_EVENTS,\n} from './OHLCVService';\nexport type {\n OHLCVSystemNotificationData,\n OHLCVServiceOptions,\n OHLCVServiceActions,\n AllowedActions as OHLCVServiceAllowedActions,\n OHLCVServiceBarUpdatedEvent,\n OHLCVServiceChainStatusChangedEvent,\n OHLCVServiceSubscriptionErrorEvent,\n OHLCVServiceEvents,\n AllowedEvents as OHLCVServiceAllowedEvents,\n OHLCVServiceMessenger,\n} from './OHLCVService';\nexport type { OHLCVBar, OHLCVSubscriptionOptions } from './types';\n"]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * OHLCV WebSocket streaming types for real-time candlestick data.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../src/ws/ohlcv/types.ts"],"names":[],"mappings":";AAAA;;GAEG","sourcesContent":["/**\n * OHLCV WebSocket streaming types for real-time candlestick data.\n */\n\n/**\n * A single OHLCV candlestick bar received from the market-data WebSocket stream.\n */\nexport type OHLCVBar = {\n /** Unix timestamp (seconds) of the candle open */\n timestamp: number;\n /** Opening price */\n open: number;\n /** Highest price during the candle period */\n high: number;\n /** Lowest price during the candle period */\n low: number;\n /** Closing price (latest) */\n close: number;\n /** Trading volume during the candle period */\n volume: number;\n};\n\n/**\n * Options for subscribing to an OHLCV channel.\n */\nexport type OHLCVSubscriptionOptions = {\n /** CAIP-19 asset identifier, e.g. \"eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" */\n assetId: string;\n /** Candle interval, e.g. \"1m\", \"5m\", \"15m\", \"1h\", \"4h\", \"1d\" */\n interval: string;\n /** Fiat currency code, e.g. \"usd\", \"eur\" */\n currency: string;\n};\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * OHLCV WebSocket streaming types for real-time candlestick data.
3
+ */
4
+ /**
5
+ * A single OHLCV candlestick bar received from the market-data WebSocket stream.
6
+ */
7
+ export type OHLCVBar = {
8
+ /** Unix timestamp (seconds) of the candle open */
9
+ timestamp: number;
10
+ /** Opening price */
11
+ open: number;
12
+ /** Highest price during the candle period */
13
+ high: number;
14
+ /** Lowest price during the candle period */
15
+ low: number;
16
+ /** Closing price (latest) */
17
+ close: number;
18
+ /** Trading volume during the candle period */
19
+ volume: number;
20
+ };
21
+ /**
22
+ * Options for subscribing to an OHLCV channel.
23
+ */
24
+ export type OHLCVSubscriptionOptions = {
25
+ /** CAIP-19 asset identifier, e.g. "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" */
26
+ assetId: string;
27
+ /** Candle interval, e.g. "1m", "5m", "15m", "1h", "4h", "1d" */
28
+ interval: string;
29
+ /** Fiat currency code, e.g. "usd", "eur" */
30
+ currency: string;
31
+ };
32
+ //# sourceMappingURL=types.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../src/ws/ohlcv/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,oGAAoG;IACpG,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC"}