@metamask-previews/core-backend 12.3.0-preview-9fd631f7d → 12.3.0-preview-6fbab7311
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.
- package/CHANGELOG.md +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/ws/ChannelSubscriptionManager.d.ts +105 -0
- package/dist/ws/ChannelSubscriptionManager.d.ts.map +1 -0
- package/dist/ws/ChannelSubscriptionManager.js +413 -0
- package/dist/ws/ChannelSubscriptionManager.js.map +1 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService-method-action-types.d.ts +35 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService-method-action-types.d.ts.map +1 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService-method-action-types.js +6 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService-method-action-types.js.map +1 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService.d.ts +115 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService.d.ts.map +1 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService.js +185 -0
- package/dist/ws/launchpad/LaunchpadTokenDetailsService.js.map +1 -0
- package/dist/ws/launchpad/index.d.ts +6 -0
- package/dist/ws/launchpad/index.d.ts.map +1 -0
- package/dist/ws/launchpad/index.js +4 -0
- package/dist/ws/launchpad/index.js.map +1 -0
- package/dist/ws/launchpad/normalize.d.ts +38 -0
- package/dist/ws/launchpad/normalize.d.ts.map +1 -0
- package/dist/ws/launchpad/normalize.js +134 -0
- package/dist/ws/launchpad/normalize.js.map +1 -0
- package/dist/ws/launchpad/types.d.ts +141 -0
- package/dist/ws/launchpad/types.d.ts.map +1 -0
- package/dist/ws/launchpad/types.js +11 -0
- package/dist/ws/launchpad/types.js.map +1 -0
- package/dist/ws/ohlcv/OHLCVService.d.ts +7 -4
- package/dist/ws/ohlcv/OHLCVService.d.ts.map +1 -1
- package/dist/ws/ohlcv/OHLCVService.js +42 -329
- package/dist/ws/ohlcv/OHLCVService.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -9,14 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- Add `LaunchpadTokenDetailsService` for real-time launchpad token detail streaming over the shared backend WebSocket, exposing `subscribe`/`unsubscribe` by `assetId` and publishing `tokenUpdated`, `statusChanged`, and `subscriptionError` events, along with `LAUNCHPAD_TDP_SERVICE_ALLOWED_ACTIONS`/`LAUNCHPAD_TDP_SERVICE_ALLOWED_EVENTS` and launchpad event types/normalizers (`parseBatch`, `normalizeEvent`, `buildChannel`) ([#10884](https://github.com/MetaMask/core/pull/10884))
|
|
13
|
+
- Add `ChannelSubscriptionManager`, a reusable per-channel WebSocket subscription lifecycle helper (reference counting, grace-period unsubscribe, unsubscribe retry, and resubscribe on reconnect) shared by `OHLCVService` and `LaunchpadTokenDetailsService` ([#10884](https://github.com/MetaMask/core/pull/10884))
|
|
12
14
|
- Add support for Node.js 26 ([#10981](https://github.com/MetaMask/core/pull/10981))
|
|
13
15
|
|
|
14
16
|
### Changed
|
|
15
17
|
|
|
18
|
+
- **BREAKING:** Remove the unused `BackendWebSocketService:getConnectionInfo` and `BackendWebSocketService:findSubscriptionsByChannelPrefix` actions from `OHLCV_SERVICE_ALLOWED_ACTIONS` ([#10884](https://github.com/MetaMask/core/pull/10884))
|
|
19
|
+
- `OHLCV_SERVICE_ALLOWED_ACTIONS` / `OHLCV_SERVICE_ALLOWED_EVENTS` and `LAUNCHPAD_TDP_SERVICE_ALLOWED_ACTIONS` / `LAUNCHPAD_TDP_SERVICE_ALLOWED_EVENTS` are now sourced from a single shared set (the `BackendWebSocketService` actions/events the `ChannelSubscriptionManager` actually calls), so both services grant identical, minimal permissions.
|
|
20
|
+
- If you build the `OHLCVService` restricted messenger from `OHLCV_SERVICE_ALLOWED_ACTIONS`, it will no longer be granted those two actions. Neither action was ever called by `OHLCVService`, so no runtime behavior changes; grant them explicitly only if your own code calls them through that messenger.
|
|
21
|
+
- Refactor `OHLCVService` to delegate its subscription lifecycle to the shared `ChannelSubscriptionManager` via composition, with no change to its public methods or published events ([#10884](https://github.com/MetaMask/core/pull/10884))
|
|
16
22
|
- Stop publishing the `api/test-utils` test helper, which was never reachable through the package's `exports` field ([#10916](https://github.com/MetaMask/core/pull/10916))
|
|
17
23
|
- Bump `@metamask/account-tree-controller` from `^11.0.1` to `^11.2.0` ([#10891](https://github.com/MetaMask/core/pull/10891), [#10925](https://github.com/MetaMask/core/pull/10925), [#11092](https://github.com/MetaMask/core/pull/11092))
|
|
18
24
|
- Bump `@metamask/profile-sync-controller` from `^34.0.3` to `^36.0.0` ([#10905](https://github.com/MetaMask/core/pull/10905), [#10925](https://github.com/MetaMask/core/pull/10925), [#11092](https://github.com/MetaMask/core/pull/11092))
|
|
19
25
|
- Bump `@metamask/utils` from `^12.0.0` to `^12.0.1` ([#11107](https://github.com/MetaMask/core/pull/11107))
|
|
26
|
+
- Bump `uuid` from `^11.1.1` to `^14.0.0` ([#10941](https://github.com/MetaMask/core/pull/10941))
|
|
20
27
|
|
|
21
28
|
## [12.3.0]
|
|
22
29
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ export { ApiPlatformClientService, apiPlatformClientServiceName, } from './ApiPl
|
|
|
7
7
|
export type { ApiPlatformClientServiceOptions, ApiPlatformClientServiceActions, ApiPlatformClientServiceEvents, ApiPlatformClientServiceMessenger, } from './ApiPlatformClientService.js';
|
|
8
8
|
export { OHLCVService, OHLCV_SERVICE_ALLOWED_ACTIONS, OHLCV_SERVICE_ALLOWED_EVENTS, } from './ws/ohlcv/index.js';
|
|
9
9
|
export type { OHLCVBar, OHLCVSubscriptionOptions, OHLCVSystemNotificationData, OHLCVServiceOptions, OHLCVServiceActions, OHLCVServiceAllowedActions, OHLCVServiceBarUpdatedEvent, OHLCVServiceChainStatusChangedEvent, OHLCVServiceSubscriptionErrorEvent, OHLCVServiceEvents, OHLCVServiceAllowedEvents, OHLCVServiceMessenger, } from './ws/ohlcv/index.js';
|
|
10
|
+
export { ChannelSubscriptionManager } from './ws/ChannelSubscriptionManager.js';
|
|
11
|
+
export type { ChannelSubscriptionManagerMessenger, ChannelSubscriptionManagerOptions, ChannelSubscriptionOperation, } from './ws/ChannelSubscriptionManager.js';
|
|
12
|
+
export { LaunchpadTokenDetailsService, LAUNCHPAD_TDP_SERVICE_ALLOWED_ACTIONS, LAUNCHPAD_TDP_SERVICE_ALLOWED_EVENTS, buildChannel, normalizeEvent, parseBatch, LAUNCHPAD_SUBSCRIPTION_NAMESPACE, } from './ws/launchpad/index.js';
|
|
13
|
+
export type { LaunchpadSystemNotificationData, LaunchpadTokenDetailsServiceOptions, LaunchpadTokenDetailsServiceActions, LaunchpadTokenDetailsServiceAllowedActions, LaunchpadTokenDetailsServiceTokenUpdatedEvent, LaunchpadTokenDetailsServiceStatusChangedEvent, LaunchpadTokenDetailsServiceSubscriptionErrorEvent, LaunchpadTokenDetailsServiceEvents, LaunchpadTokenDetailsServiceAllowedEvents, LaunchpadTokenDetailsServiceMessenger, LaunchpadEventType, RawLaunchpadTokenEvent, LaunchpadTokenCreatedEvent, LaunchpadTokenStatsEvent, LaunchpadTokenMigratedEvent, LaunchpadTokenEvent, LaunchpadTokenDetailsSubscriptionOptions, } from './ws/launchpad/index.js';
|
|
10
14
|
export { ApiPlatformClient, createApiPlatformClient, AccountsApiClient, PricesApiClient, TokenApiClient, TokensApiClient, API_URLS, STALE_TIMES, GC_TIMES, V6_DEFI_POSITION_TYPES, calculateRetryDelay, getQueryOptionsOverrides, shouldRetry, HttpError, } from './api/index.js';
|
|
11
15
|
export type { ApiPlatformClientOptions, ApiUrls, FetchOptions, PageInfo, SupportedCurrency, MarketDataDetails, V5BalanceItem, V5BalancesResponse, V2BalanceItem, V2BalancesResponse, V4BalancesResponse, V6VsCurrency, V6DeFiPositionType, V6BalanceMetadata, V6StellarTokenBalanceMetadata, V6TokenBalanceMetadata, V6BalanceItem, V6BalancesResponse, V1SupportedNetworksResponse, V2SupportedNetworksResponse, V2ActiveNetworksResponse, V1TransactionByHashResponse, V1AccountTransactionsResponse, V4MultiAccountTransactionsResponse, ValueTransfer, V1AccountRelationshipResult, NftItem, V2NftsResponse, TokenDiscoveryItem, V2TokensResponse, V3SpotPricesResponse, CoinGeckoSpotPrice, ExchangeRateInfo, V1ExchangeRatesResponse, PriceSupportedNetworksResponse, PriceV1SupportedNetworksResponse, PriceV2SupportedNetworksResponse, V1HistoricalPricesResponse, V3HistoricalPricesResponse, TokenMetadata, TokenListQueryOptions, TokenV2SupportedNetworksResponse, V1TokenDescriptionResponse, NetworkInfo, TopAsset, TrendingSortBy, TrendingToken, TopGainersSortOption, TrendingSortOption, V1SuggestedOccurrenceFloorsResponse, V1TokenSupportedNetworksResponse, V2TokenSupportedNetworksResponse, V3AssetResponse, } from './api/index.js';
|
|
12
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AAEzC,YAAY,EACV,8BAA8B,EAC9B,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,8BAA8B,EAC9B,kDAAkD,EAClD,6BAA6B,EAC7B,gCAAgC,GACjC,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EACL,sBAAsB,EACtB,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,gCAAgC,CAAC;AAExC,YAAY,EACV,sBAAsB,EACtB,mBAAmB,EACnB,6BAA6B,EAC7B,6BAA6B,EAC7B,cAAc,IAAI,oCAAoC,EACtD,6CAA6C,EAC7C,yCAAyC,EACzC,4CAA4C,EAC5C,wCAAwC,EACxC,4BAA4B,EAC5B,aAAa,IAAI,mCAAmC,EACpD,+BAA+B,GAChC,MAAM,gCAAgC,CAAC;AAMxC,YAAY,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,QAAQ,EACR,aAAa,EACb,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAMpB,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACV,+BAA+B,EAC/B,+BAA+B,EAC/B,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,+BAA+B,CAAC;AAMvC,OAAO,EACL,YAAY,EACZ,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,QAAQ,EACR,wBAAwB,EACxB,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,EAC3B,mCAAmC,EACnC,kCAAkC,EAClC,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EAEvB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,eAAe,EAEf,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,sBAAsB,EAEtB,mBAAmB,EACnB,wBAAwB,EACxB,WAAW,EAEX,SAAS,GACV,MAAM,gBAAgB,CAAC;AAMxB,YAAY,EAEV,wBAAwB,EACxB,OAAO,EACP,YAAY,EAEZ,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EAEjB,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,sBAAsB,EACtB,aAAa,EACb,kBAAkB,EAClB,2BAA2B,EAC3B,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,EAC7B,kCAAkC,EAClC,aAAa,EACb,2BAA2B,EAC3B,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEhB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,8BAA8B,EAC9B,gCAAgC,EAChC,gCAAgC,EAChC,0BAA0B,EAC1B,0BAA0B,EAE1B,aAAa,EACb,qBAAqB,EACrB,gCAAgC,EAChC,0BAA0B,EAC1B,WAAW,EACX,QAAQ,EACR,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,mCAAmC,EAEnC,gCAAgC,EAChC,gCAAgC,EAChC,eAAe,GAChB,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,14 @@ export { ApiPlatformClientService, apiPlatformClientServiceName, } from './ApiPl
|
|
|
16
16
|
// ============================================================================
|
|
17
17
|
export { OHLCVService, OHLCV_SERVICE_ALLOWED_ACTIONS, OHLCV_SERVICE_ALLOWED_EVENTS, } from './ws/ohlcv/index.js';
|
|
18
18
|
// ============================================================================
|
|
19
|
+
// CHANNEL SUBSCRIPTION MANAGER
|
|
20
|
+
// ============================================================================
|
|
21
|
+
export { ChannelSubscriptionManager } from './ws/ChannelSubscriptionManager.js';
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// LAUNCHPAD TOKEN DETAILS SERVICE
|
|
24
|
+
// ============================================================================
|
|
25
|
+
export { LaunchpadTokenDetailsService, LAUNCHPAD_TDP_SERVICE_ALLOWED_ACTIONS, LAUNCHPAD_TDP_SERVICE_ALLOWED_EVENTS, buildChannel, normalizeEvent, parseBatch, LAUNCHPAD_SUBSCRIPTION_NAMESPACE, } from './ws/launchpad/index.js';
|
|
26
|
+
// ============================================================================
|
|
19
27
|
// API PLATFORM CLIENT
|
|
20
28
|
// ============================================================================
|
|
21
29
|
export { ApiPlatformClient, createApiPlatformClient,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,+EAA+E;AAC/E,4BAA4B;AAC5B,+EAA+E;AAE/E,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AAiBzC,+EAA+E;AAC/E,2BAA2B;AAC3B,+EAA+E;AAE/E,OAAO,EACL,sBAAsB,EACtB,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,gCAAgC,CAAC;AA8BxC,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;AASvC,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E,OAAO,EACL,YAAY,EACZ,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAiB7B,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,OAAO,EACL,iBAAiB,EACjB,uBAAuB;AACvB,yBAAyB;AACzB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,eAAe;AACf,YAAY;AACZ,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,sBAAsB;AACtB,UAAU;AACV,mBAAmB,EACnB,wBAAwB,EACxB,WAAW;AACX,SAAS;AACT,SAAS,GACV,MAAM,gBAAgB,CAAC","sourcesContent":["// Core Backend Package Exports\n\n// ============================================================================\n// BACKEND WEBSOCKET SERVICE\n// ============================================================================\n\nexport {\n BackendWebSocketService,\n getCloseReason,\n WebSocketState,\n WebSocketEventType,\n} from './ws/BackendWebSocketService.js';\n\nexport type {\n BackendWebSocketServiceOptions,\n ClientRequestMessage,\n ServerResponseMessage,\n ServerNotificationMessage,\n WebSocketMessage,\n ChannelCallback,\n WebSocketSubscription,\n WebSocketConnectionInfo,\n BackendWebSocketServiceActions,\n BackendWebSocketServiceConnectionStateChangedEvent,\n BackendWebSocketServiceEvents,\n BackendWebSocketServiceMessenger,\n} from './ws/BackendWebSocketService.js';\n\n// ============================================================================\n// ACCOUNT ACTIVITY SERVICE\n// ============================================================================\n\nexport {\n AccountActivityService,\n ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS,\n ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS,\n} from './ws/AccountActivityService.js';\n\nexport type {\n SystemNotificationData,\n SubscriptionOptions,\n AccountActivityServiceOptions,\n AccountActivityServiceActions,\n AllowedActions as AccountActivityServiceAllowedActions,\n AccountActivityServiceTransactionUpdatedEvent,\n AccountActivityServiceBalanceUpdatedEvent,\n AccountActivityServiceSubscriptionErrorEvent,\n AccountActivityServiceStatusChangedEvent,\n AccountActivityServiceEvents,\n AllowedEvents as AccountActivityServiceAllowedEvents,\n AccountActivityServiceMessenger,\n} from './ws/AccountActivityService.js';\n\n// ============================================================================\n// SHARED TYPES\n// ============================================================================\n\nexport type {\n Transaction,\n Asset,\n Balance,\n Transfer,\n BalanceUpdate,\n AccountActivityMessage,\n} from './types.js';\n\n// ============================================================================\n// API PLATFORM CLIENT SERVICE\n// ============================================================================\n\nexport {\n ApiPlatformClientService,\n apiPlatformClientServiceName,\n} from './ApiPlatformClientService.js';\n\nexport type {\n ApiPlatformClientServiceOptions,\n ApiPlatformClientServiceActions,\n ApiPlatformClientServiceEvents,\n ApiPlatformClientServiceMessenger,\n} from './ApiPlatformClientService.js';\n\n// ============================================================================\n// OHLCV SERVICE\n// ============================================================================\n\nexport {\n OHLCVService,\n OHLCV_SERVICE_ALLOWED_ACTIONS,\n OHLCV_SERVICE_ALLOWED_EVENTS,\n} from './ws/ohlcv/index.js';\n\nexport type {\n OHLCVBar,\n OHLCVSubscriptionOptions,\n OHLCVSystemNotificationData,\n OHLCVServiceOptions,\n OHLCVServiceActions,\n OHLCVServiceAllowedActions,\n OHLCVServiceBarUpdatedEvent,\n OHLCVServiceChainStatusChangedEvent,\n OHLCVServiceSubscriptionErrorEvent,\n OHLCVServiceEvents,\n OHLCVServiceAllowedEvents,\n OHLCVServiceMessenger,\n} from './ws/ohlcv/index.js';\n\n// ============================================================================\n// API PLATFORM CLIENT\n// ============================================================================\n\nexport {\n ApiPlatformClient,\n createApiPlatformClient,\n // Individual API clients\n AccountsApiClient,\n PricesApiClient,\n TokenApiClient,\n TokensApiClient,\n // Constants\n API_URLS,\n STALE_TIMES,\n GC_TIMES,\n V6_DEFI_POSITION_TYPES,\n // Helpers\n calculateRetryDelay,\n getQueryOptionsOverrides,\n shouldRetry,\n // Errors\n HttpError,\n} from './api/index.js';\n\n// ============================================================================\n// API PLATFORM CLIENT TYPES\n// ============================================================================\n\nexport type {\n // Client options\n ApiPlatformClientOptions,\n ApiUrls,\n FetchOptions,\n // Shared types\n PageInfo,\n SupportedCurrency,\n MarketDataDetails,\n // Accounts API types\n V5BalanceItem,\n V5BalancesResponse,\n V2BalanceItem,\n V2BalancesResponse,\n V4BalancesResponse,\n V6VsCurrency,\n V6DeFiPositionType,\n V6BalanceMetadata,\n V6StellarTokenBalanceMetadata,\n V6TokenBalanceMetadata,\n V6BalanceItem,\n V6BalancesResponse,\n V1SupportedNetworksResponse,\n V2SupportedNetworksResponse,\n V2ActiveNetworksResponse,\n V1TransactionByHashResponse,\n V1AccountTransactionsResponse,\n V4MultiAccountTransactionsResponse,\n ValueTransfer,\n V1AccountRelationshipResult,\n NftItem,\n V2NftsResponse,\n TokenDiscoveryItem,\n V2TokensResponse,\n // Prices API types\n V3SpotPricesResponse,\n CoinGeckoSpotPrice,\n ExchangeRateInfo,\n V1ExchangeRatesResponse,\n PriceSupportedNetworksResponse,\n PriceV1SupportedNetworksResponse,\n PriceV2SupportedNetworksResponse,\n V1HistoricalPricesResponse,\n V3HistoricalPricesResponse,\n // Token API types\n TokenMetadata,\n TokenListQueryOptions,\n TokenV2SupportedNetworksResponse,\n V1TokenDescriptionResponse,\n NetworkInfo,\n TopAsset,\n TrendingSortBy,\n TrendingToken,\n TopGainersSortOption,\n TrendingSortOption,\n V1SuggestedOccurrenceFloorsResponse,\n // Tokens API types\n V1TokenSupportedNetworksResponse,\n V2TokenSupportedNetworksResponse,\n V3AssetResponse,\n} from './api/index.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,+EAA+E;AAC/E,4BAA4B;AAC5B,+EAA+E;AAE/E,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AAiBzC,+EAA+E;AAC/E,2BAA2B;AAC3B,+EAA+E;AAE/E,OAAO,EACL,sBAAsB,EACtB,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,gCAAgC,CAAC;AA8BxC,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;AASvC,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E,OAAO,EACL,YAAY,EACZ,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAiB7B,+EAA+E;AAC/E,+BAA+B;AAC/B,+EAA+E;AAE/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAQhF,+EAA+E;AAC/E,kCAAkC;AAClC,+EAA+E;AAE/E,OAAO,EACL,4BAA4B,EAC5B,qCAAqC,EACrC,oCAAoC,EACpC,YAAY,EACZ,cAAc,EACd,UAAU,EACV,gCAAgC,GACjC,MAAM,yBAAyB,CAAC;AAsBjC,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,OAAO,EACL,iBAAiB,EACjB,uBAAuB;AACvB,yBAAyB;AACzB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,eAAe;AACf,YAAY;AACZ,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,sBAAsB;AACtB,UAAU;AACV,mBAAmB,EACnB,wBAAwB,EACxB,WAAW;AACX,SAAS;AACT,SAAS,GACV,MAAM,gBAAgB,CAAC","sourcesContent":["// Core Backend Package Exports\n\n// ============================================================================\n// BACKEND WEBSOCKET SERVICE\n// ============================================================================\n\nexport {\n BackendWebSocketService,\n getCloseReason,\n WebSocketState,\n WebSocketEventType,\n} from './ws/BackendWebSocketService.js';\n\nexport type {\n BackendWebSocketServiceOptions,\n ClientRequestMessage,\n ServerResponseMessage,\n ServerNotificationMessage,\n WebSocketMessage,\n ChannelCallback,\n WebSocketSubscription,\n WebSocketConnectionInfo,\n BackendWebSocketServiceActions,\n BackendWebSocketServiceConnectionStateChangedEvent,\n BackendWebSocketServiceEvents,\n BackendWebSocketServiceMessenger,\n} from './ws/BackendWebSocketService.js';\n\n// ============================================================================\n// ACCOUNT ACTIVITY SERVICE\n// ============================================================================\n\nexport {\n AccountActivityService,\n ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS,\n ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS,\n} from './ws/AccountActivityService.js';\n\nexport type {\n SystemNotificationData,\n SubscriptionOptions,\n AccountActivityServiceOptions,\n AccountActivityServiceActions,\n AllowedActions as AccountActivityServiceAllowedActions,\n AccountActivityServiceTransactionUpdatedEvent,\n AccountActivityServiceBalanceUpdatedEvent,\n AccountActivityServiceSubscriptionErrorEvent,\n AccountActivityServiceStatusChangedEvent,\n AccountActivityServiceEvents,\n AllowedEvents as AccountActivityServiceAllowedEvents,\n AccountActivityServiceMessenger,\n} from './ws/AccountActivityService.js';\n\n// ============================================================================\n// SHARED TYPES\n// ============================================================================\n\nexport type {\n Transaction,\n Asset,\n Balance,\n Transfer,\n BalanceUpdate,\n AccountActivityMessage,\n} from './types.js';\n\n// ============================================================================\n// API PLATFORM CLIENT SERVICE\n// ============================================================================\n\nexport {\n ApiPlatformClientService,\n apiPlatformClientServiceName,\n} from './ApiPlatformClientService.js';\n\nexport type {\n ApiPlatformClientServiceOptions,\n ApiPlatformClientServiceActions,\n ApiPlatformClientServiceEvents,\n ApiPlatformClientServiceMessenger,\n} from './ApiPlatformClientService.js';\n\n// ============================================================================\n// OHLCV SERVICE\n// ============================================================================\n\nexport {\n OHLCVService,\n OHLCV_SERVICE_ALLOWED_ACTIONS,\n OHLCV_SERVICE_ALLOWED_EVENTS,\n} from './ws/ohlcv/index.js';\n\nexport type {\n OHLCVBar,\n OHLCVSubscriptionOptions,\n OHLCVSystemNotificationData,\n OHLCVServiceOptions,\n OHLCVServiceActions,\n OHLCVServiceAllowedActions,\n OHLCVServiceBarUpdatedEvent,\n OHLCVServiceChainStatusChangedEvent,\n OHLCVServiceSubscriptionErrorEvent,\n OHLCVServiceEvents,\n OHLCVServiceAllowedEvents,\n OHLCVServiceMessenger,\n} from './ws/ohlcv/index.js';\n\n// ============================================================================\n// CHANNEL SUBSCRIPTION MANAGER\n// ============================================================================\n\nexport { ChannelSubscriptionManager } from './ws/ChannelSubscriptionManager.js';\n\nexport type {\n ChannelSubscriptionManagerMessenger,\n ChannelSubscriptionManagerOptions,\n ChannelSubscriptionOperation,\n} from './ws/ChannelSubscriptionManager.js';\n\n// ============================================================================\n// LAUNCHPAD TOKEN DETAILS SERVICE\n// ============================================================================\n\nexport {\n LaunchpadTokenDetailsService,\n LAUNCHPAD_TDP_SERVICE_ALLOWED_ACTIONS,\n LAUNCHPAD_TDP_SERVICE_ALLOWED_EVENTS,\n buildChannel,\n normalizeEvent,\n parseBatch,\n LAUNCHPAD_SUBSCRIPTION_NAMESPACE,\n} from './ws/launchpad/index.js';\n\nexport type {\n LaunchpadSystemNotificationData,\n LaunchpadTokenDetailsServiceOptions,\n LaunchpadTokenDetailsServiceActions,\n LaunchpadTokenDetailsServiceAllowedActions,\n LaunchpadTokenDetailsServiceTokenUpdatedEvent,\n LaunchpadTokenDetailsServiceStatusChangedEvent,\n LaunchpadTokenDetailsServiceSubscriptionErrorEvent,\n LaunchpadTokenDetailsServiceEvents,\n LaunchpadTokenDetailsServiceAllowedEvents,\n LaunchpadTokenDetailsServiceMessenger,\n LaunchpadEventType,\n RawLaunchpadTokenEvent,\n LaunchpadTokenCreatedEvent,\n LaunchpadTokenStatsEvent,\n LaunchpadTokenMigratedEvent,\n LaunchpadTokenEvent,\n LaunchpadTokenDetailsSubscriptionOptions,\n} from './ws/launchpad/index.js';\n\n// ============================================================================\n// API PLATFORM CLIENT\n// ============================================================================\n\nexport {\n ApiPlatformClient,\n createApiPlatformClient,\n // Individual API clients\n AccountsApiClient,\n PricesApiClient,\n TokenApiClient,\n TokensApiClient,\n // Constants\n API_URLS,\n STALE_TIMES,\n GC_TIMES,\n V6_DEFI_POSITION_TYPES,\n // Helpers\n calculateRetryDelay,\n getQueryOptionsOverrides,\n shouldRetry,\n // Errors\n HttpError,\n} from './api/index.js';\n\n// ============================================================================\n// API PLATFORM CLIENT TYPES\n// ============================================================================\n\nexport type {\n // Client options\n ApiPlatformClientOptions,\n ApiUrls,\n FetchOptions,\n // Shared types\n PageInfo,\n SupportedCurrency,\n MarketDataDetails,\n // Accounts API types\n V5BalanceItem,\n V5BalancesResponse,\n V2BalanceItem,\n V2BalancesResponse,\n V4BalancesResponse,\n V6VsCurrency,\n V6DeFiPositionType,\n V6BalanceMetadata,\n V6StellarTokenBalanceMetadata,\n V6TokenBalanceMetadata,\n V6BalanceItem,\n V6BalancesResponse,\n V1SupportedNetworksResponse,\n V2SupportedNetworksResponse,\n V2ActiveNetworksResponse,\n V1TransactionByHashResponse,\n V1AccountTransactionsResponse,\n V4MultiAccountTransactionsResponse,\n ValueTransfer,\n V1AccountRelationshipResult,\n NftItem,\n V2NftsResponse,\n TokenDiscoveryItem,\n V2TokensResponse,\n // Prices API types\n V3SpotPricesResponse,\n CoinGeckoSpotPrice,\n ExchangeRateInfo,\n V1ExchangeRatesResponse,\n PriceSupportedNetworksResponse,\n PriceV1SupportedNetworksResponse,\n PriceV2SupportedNetworksResponse,\n V1HistoricalPricesResponse,\n V3HistoricalPricesResponse,\n // Token API types\n TokenMetadata,\n TokenListQueryOptions,\n TokenV2SupportedNetworksResponse,\n V1TokenDescriptionResponse,\n NetworkInfo,\n TopAsset,\n TrendingSortBy,\n TrendingToken,\n TopGainersSortOption,\n TrendingSortOption,\n V1SuggestedOccurrenceFloorsResponse,\n // Tokens API types\n V1TokenSupportedNetworksResponse,\n V2TokenSupportedNetworksResponse,\n V3AssetResponse,\n} from './api/index.js';\n"]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared per-channel WebSocket subscription lifecycle manager.
|
|
3
|
+
*
|
|
4
|
+
* Extracts the channel-agnostic subscription machinery that was originally part
|
|
5
|
+
* of {@link OHLCVService}: reference counting, grace-period unsubscribe,
|
|
6
|
+
* grace-period flush, unsubscribe retry with backoff + force reconnection,
|
|
7
|
+
* idempotency checks, resubscribe-on-reconnect, and optional system-notification
|
|
8
|
+
* channel registration.
|
|
9
|
+
*
|
|
10
|
+
* It is consumed by **composition** (not inheritance). Each domain service
|
|
11
|
+
* (e.g. OHLCV market data, Launchpad token details) constructs a manager,
|
|
12
|
+
* provides the channel-type namespace and a per-message callback, and keeps its
|
|
13
|
+
* own domain concerns (channel-string construction, payload parsing, published
|
|
14
|
+
* events). The manager talks to {@link BackendWebSocketService} exclusively
|
|
15
|
+
* through the messenger — no direct import of the class.
|
|
16
|
+
*/
|
|
17
|
+
import type { Messenger } from '@metamask/messenger';
|
|
18
|
+
import type { BackendWebSocketServiceMethodActions } from './BackendWebSocketService-method-action-types.js';
|
|
19
|
+
import type { WebSocketConnectionInfo, BackendWebSocketServiceConnectionStateChangedEvent, ServerNotificationMessage } from './BackendWebSocketService.js';
|
|
20
|
+
/**
|
|
21
|
+
* The `BackendWebSocketService:*` actions the manager calls through its host
|
|
22
|
+
* service's messenger. A domain service must grant (at least) these to its
|
|
23
|
+
* restricted messenger, since the manager borrows that messenger and performs
|
|
24
|
+
* all WebSocket calls on the service's behalf. Services should source their own
|
|
25
|
+
* `*_ALLOWED_ACTIONS` export from this list rather than re-declaring it.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CHANNEL_SUBSCRIPTION_MANAGER_ALLOWED_ACTIONS: readonly ['BackendWebSocketService:connect', 'BackendWebSocketService:forceReconnection', 'BackendWebSocketService:subscribe', 'BackendWebSocketService:channelHasSubscription', 'BackendWebSocketService:getSubscriptionsByChannel', 'BackendWebSocketService:addChannelCallback', 'BackendWebSocketService:removeChannelCallback'];
|
|
28
|
+
/**
|
|
29
|
+
* The `BackendWebSocketService:*` events the manager subscribes to through its
|
|
30
|
+
* host service's messenger.
|
|
31
|
+
*/
|
|
32
|
+
export declare const CHANNEL_SUBSCRIPTION_MANAGER_ALLOWED_EVENTS: readonly ['BackendWebSocketService:connectionStateChanged'];
|
|
33
|
+
/**
|
|
34
|
+
* Minimal messenger shape the manager requires: the `BackendWebSocketService:*`
|
|
35
|
+
* actions and the `connectionStateChanged` event. A host service's messenger
|
|
36
|
+
* (which has these delegated plus its own domain actions/events) satisfies this.
|
|
37
|
+
*/
|
|
38
|
+
export type ChannelSubscriptionManagerMessenger = Messenger<string, BackendWebSocketServiceMethodActions, BackendWebSocketServiceConnectionStateChangedEvent>;
|
|
39
|
+
/** The kind of operation that failed, forwarded to `onSubscriptionError`. */
|
|
40
|
+
export type ChannelSubscriptionOperation = 'subscribe' | 'unsubscribe';
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for a {@link ChannelSubscriptionManager}.
|
|
43
|
+
*/
|
|
44
|
+
export type ChannelSubscriptionManagerOptions = {
|
|
45
|
+
/** Messenger used to reach {@link BackendWebSocketService}. */
|
|
46
|
+
messenger: ChannelSubscriptionManagerMessenger;
|
|
47
|
+
/** Channel type/namespace passed to `BackendWebSocketService:subscribe`. */
|
|
48
|
+
channelType: string;
|
|
49
|
+
/** Called for each subscription notification on a managed channel. */
|
|
50
|
+
onMessage: (channel: string, notification: ServerNotificationMessage) => void;
|
|
51
|
+
/** Called when a subscribe/unsubscribe operation fails. */
|
|
52
|
+
onSubscriptionError?: (channel: string, error: string, operation: ChannelSubscriptionOperation) => void;
|
|
53
|
+
/** Optional system-notifications channel to register a callback for on `init()`. */
|
|
54
|
+
systemNotificationsChannel?: string;
|
|
55
|
+
/** Handler invoked for messages on the system-notifications channel. */
|
|
56
|
+
onSystemNotification?: (notification: ServerNotificationMessage) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Called on every connection state change, after the manager performs its own
|
|
59
|
+
* resubscribe-on-CONNECTED. Lets the host run domain reactions (e.g. marking
|
|
60
|
+
* tracked chains down on DISCONNECTED).
|
|
61
|
+
*/
|
|
62
|
+
onConnectionStateChange?: (connectionInfo: WebSocketConnectionInfo) => void;
|
|
63
|
+
/** Prefix used in log lines (defaults to the channel type). */
|
|
64
|
+
logPrefix?: string;
|
|
65
|
+
/** Override the grace period (primarily for tests). */
|
|
66
|
+
gracePeriodMs?: number;
|
|
67
|
+
/** Override the unsubscribe retry backoff delays (primarily for tests). */
|
|
68
|
+
unsubRetryDelaysMs?: number[];
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Manages the lifecycle of per-channel WebSocket subscriptions on top of the
|
|
72
|
+
* shared {@link BackendWebSocketService}.
|
|
73
|
+
*/
|
|
74
|
+
export declare class ChannelSubscriptionManager {
|
|
75
|
+
#private;
|
|
76
|
+
constructor(options: ChannelSubscriptionManagerOptions);
|
|
77
|
+
/**
|
|
78
|
+
* Register the system-notifications channel callback, if configured.
|
|
79
|
+
*/
|
|
80
|
+
init(): void;
|
|
81
|
+
/**
|
|
82
|
+
* Subscribe to a channel. If this is the first subscriber a WebSocket
|
|
83
|
+
* subscription is created; additional calls for the same channel only bump the
|
|
84
|
+
* reference count.
|
|
85
|
+
*
|
|
86
|
+
* @param channel - The fully-qualified channel name.
|
|
87
|
+
* @returns A promise that resolves once the subscription is established.
|
|
88
|
+
*/
|
|
89
|
+
subscribe(channel: string): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Unsubscribe from a channel. Decrements the reference count and, when it
|
|
92
|
+
* reaches zero, starts a grace-period timer before actually unsubscribing from
|
|
93
|
+
* the WebSocket to absorb rapid navigation patterns.
|
|
94
|
+
*
|
|
95
|
+
* @param channel - The fully-qualified channel name.
|
|
96
|
+
* @returns A promise that resolves once the unsubscription is processed.
|
|
97
|
+
*/
|
|
98
|
+
unsubscribe(channel: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Tear down all channel timers and, if configured, remove the
|
|
101
|
+
* system-notifications channel callback.
|
|
102
|
+
*/
|
|
103
|
+
destroy(): void;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=ChannelSubscriptionManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChannelSubscriptionManager.d.ts","sourceRoot":"","sources":["../../src/ws/ChannelSubscriptionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,kDAAkD,CAAC;AAC7G,OAAO,KAAK,EACV,uBAAuB,EACvB,kDAAkD,EAClD,yBAAyB,EAC1B,MAAM,8BAA8B,CAAC;AAatC;;;;;;GAMG;AACH,eAAO,MAAM,4CAA4C,YACvD,iCAAiC,EACjC,2CAA2C,EAC3C,mCAAmC,EACnC,gDAAgD,EAChD,mDAAmD,EACnD,4CAA4C,EAC5C,+CAA+C,CACvC,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,2CAA2C,YACtD,gDAAgD,CACxC,CAAC;AAYX;;;;GAIG;AACH,MAAM,MAAM,mCAAmC,GAAG,SAAS,CACzD,MAAM,EACN,oCAAoC,EACpC,kDAAkD,CACnD,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,4BAA4B,GAAG,WAAW,GAAG,aAAa,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,+DAA+D;IAC/D,SAAS,EAAE,mCAAmC,CAAC;IAC/C,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,yBAAyB,KAAK,IAAI,CAAC;IAC9E,2DAA2D;IAC3D,mBAAmB,CAAC,EAAE,CACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,4BAA4B,KACpC,IAAI,CAAC;IACV,oFAAoF;IACpF,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACzE;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,CAAC,cAAc,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC5E,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AAMF;;;GAGG;AACH,qBAAa,0BAA0B;;IAiBrC,YAAY,OAAO,EAAE,iCAAiC,EAgCrD;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,CAWX;IAMD;;;;;;;OAOG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9C;IA2FD;;;;;;;OAOG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhD;IAiPD;;;OAGG;IACH,OAAO,IAAI,IAAI,CAad;CACF"}
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared per-channel WebSocket subscription lifecycle manager.
|
|
3
|
+
*
|
|
4
|
+
* Extracts the channel-agnostic subscription machinery that was originally part
|
|
5
|
+
* of {@link OHLCVService}: reference counting, grace-period unsubscribe,
|
|
6
|
+
* grace-period flush, unsubscribe retry with backoff + force reconnection,
|
|
7
|
+
* idempotency checks, resubscribe-on-reconnect, and optional system-notification
|
|
8
|
+
* channel registration.
|
|
9
|
+
*
|
|
10
|
+
* It is consumed by **composition** (not inheritance). Each domain service
|
|
11
|
+
* (e.g. OHLCV market data, Launchpad token details) constructs a manager,
|
|
12
|
+
* provides the channel-type namespace and a per-message callback, and keeps its
|
|
13
|
+
* own domain concerns (channel-string construction, payload parsing, published
|
|
14
|
+
* events). The manager talks to {@link BackendWebSocketService} exclusively
|
|
15
|
+
* through the messenger — no direct import of the class.
|
|
16
|
+
*/
|
|
17
|
+
import { Mutex } from 'async-mutex';
|
|
18
|
+
import { handleAll, IterableBackoff, retry } from 'cockatiel';
|
|
19
|
+
import { projectLogger, createModuleLogger } from '../logger.js';
|
|
20
|
+
import { WebSocketState } from './BackendWebSocketService.js';
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Constants
|
|
23
|
+
// =============================================================================
|
|
24
|
+
/** Default delay before actually unsubscribing after refCount reaches 0. */
|
|
25
|
+
const DEFAULT_GRACE_PERIOD_MS = 3_000;
|
|
26
|
+
/** Default backoff delays between failed WebSocket unsubscribe attempts. */
|
|
27
|
+
const DEFAULT_UNSUB_RETRY_DELAYS_MS = [1_000, 2_000, 4_000];
|
|
28
|
+
/**
|
|
29
|
+
* The `BackendWebSocketService:*` actions the manager calls through its host
|
|
30
|
+
* service's messenger. A domain service must grant (at least) these to its
|
|
31
|
+
* restricted messenger, since the manager borrows that messenger and performs
|
|
32
|
+
* all WebSocket calls on the service's behalf. Services should source their own
|
|
33
|
+
* `*_ALLOWED_ACTIONS` export from this list rather than re-declaring it.
|
|
34
|
+
*/
|
|
35
|
+
export const CHANNEL_SUBSCRIPTION_MANAGER_ALLOWED_ACTIONS = [
|
|
36
|
+
'BackendWebSocketService:connect',
|
|
37
|
+
'BackendWebSocketService:forceReconnection',
|
|
38
|
+
'BackendWebSocketService:subscribe',
|
|
39
|
+
'BackendWebSocketService:channelHasSubscription',
|
|
40
|
+
'BackendWebSocketService:getSubscriptionsByChannel',
|
|
41
|
+
'BackendWebSocketService:addChannelCallback',
|
|
42
|
+
'BackendWebSocketService:removeChannelCallback',
|
|
43
|
+
];
|
|
44
|
+
/**
|
|
45
|
+
* The `BackendWebSocketService:*` events the manager subscribes to through its
|
|
46
|
+
* host service's messenger.
|
|
47
|
+
*/
|
|
48
|
+
export const CHANNEL_SUBSCRIPTION_MANAGER_ALLOWED_EVENTS = [
|
|
49
|
+
'BackendWebSocketService:connectionStateChanged',
|
|
50
|
+
];
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// Class
|
|
53
|
+
// =============================================================================
|
|
54
|
+
/**
|
|
55
|
+
* Manages the lifecycle of per-channel WebSocket subscriptions on top of the
|
|
56
|
+
* shared {@link BackendWebSocketService}.
|
|
57
|
+
*/
|
|
58
|
+
export class ChannelSubscriptionManager {
|
|
59
|
+
#messenger;
|
|
60
|
+
#options;
|
|
61
|
+
#channelType;
|
|
62
|
+
#channels = new Map();
|
|
63
|
+
#mutex = new Mutex();
|
|
64
|
+
#gracePeriodMs;
|
|
65
|
+
#log;
|
|
66
|
+
#unsubRetryPolicy;
|
|
67
|
+
constructor(options) {
|
|
68
|
+
this.#options = options;
|
|
69
|
+
this.#messenger = options.messenger;
|
|
70
|
+
this.#channelType = options.channelType;
|
|
71
|
+
this.#gracePeriodMs = options.gracePeriodMs ?? DEFAULT_GRACE_PERIOD_MS;
|
|
72
|
+
const retryDelays = options.unsubRetryDelaysMs ?? [
|
|
73
|
+
...DEFAULT_UNSUB_RETRY_DELAYS_MS,
|
|
74
|
+
];
|
|
75
|
+
this.#unsubRetryPolicy = retry(handleAll, {
|
|
76
|
+
// Cockatiel stops retrying once the failure index reaches `maxAttempts`,
|
|
77
|
+
// so `length` yields one initial attempt plus the delayed retries.
|
|
78
|
+
maxAttempts: retryDelays.length,
|
|
79
|
+
backoff: new IterableBackoff([...retryDelays]),
|
|
80
|
+
});
|
|
81
|
+
const prefix = options.logPrefix ?? options.channelType;
|
|
82
|
+
const moduleLog = createModuleLogger(projectLogger, 'ChannelSubscriptionManager');
|
|
83
|
+
this.#log = (message, data) => data === undefined
|
|
84
|
+
? moduleLog(`${prefix}: ${message}`)
|
|
85
|
+
: moduleLog(`${prefix}: ${message}`, data);
|
|
86
|
+
this.#messenger.subscribe('BackendWebSocketService:connectionStateChanged',
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
88
|
+
(connectionInfo) => this.#handleWebSocketStateChange(connectionInfo));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Register the system-notifications channel callback, if configured.
|
|
92
|
+
*/
|
|
93
|
+
init() {
|
|
94
|
+
const { systemNotificationsChannel, onSystemNotification } = this.#options;
|
|
95
|
+
if (!systemNotificationsChannel || !onSystemNotification) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.#log('Initializing — registering system-notifications callback');
|
|
99
|
+
this.#messenger.call('BackendWebSocketService:addChannelCallback', {
|
|
100
|
+
channelName: systemNotificationsChannel,
|
|
101
|
+
callback: (notification) => onSystemNotification(notification),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// Public — Subscribe / Unsubscribe
|
|
106
|
+
// =============================================================================
|
|
107
|
+
/**
|
|
108
|
+
* Subscribe to a channel. If this is the first subscriber a WebSocket
|
|
109
|
+
* subscription is created; additional calls for the same channel only bump the
|
|
110
|
+
* reference count.
|
|
111
|
+
*
|
|
112
|
+
* @param channel - The fully-qualified channel name.
|
|
113
|
+
* @returns A promise that resolves once the subscription is established.
|
|
114
|
+
*/
|
|
115
|
+
async subscribe(channel) {
|
|
116
|
+
const releaseLock = await this.#mutex.acquire();
|
|
117
|
+
try {
|
|
118
|
+
await this.#subscribeInner(channel);
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
releaseLock();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async #subscribeInner(channel) {
|
|
125
|
+
const entry = this.#channels.get(channel);
|
|
126
|
+
if (entry?.retryAbort) {
|
|
127
|
+
entry.retryAbort.abort();
|
|
128
|
+
entry.retryAbort = undefined;
|
|
129
|
+
entry.refCount = 1;
|
|
130
|
+
if (this.#messenger.call('BackendWebSocketService:channelHasSubscription', channel)) {
|
|
131
|
+
await this.#flushOtherChannels(channel);
|
|
132
|
+
this.#log('Cancelled unsubscribe retry — reusing WS subscription', {
|
|
133
|
+
channel,
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// WS subscription was lost — fall through to recreate it.
|
|
138
|
+
}
|
|
139
|
+
else if (entry?.gracePeriodTimer) {
|
|
140
|
+
clearTimeout(entry.gracePeriodTimer);
|
|
141
|
+
entry.gracePeriodTimer = undefined;
|
|
142
|
+
this.#log('Cancelled grace-period unsubscribe', {
|
|
143
|
+
channel,
|
|
144
|
+
});
|
|
145
|
+
if (this.#messenger.call('BackendWebSocketService:channelHasSubscription', channel)) {
|
|
146
|
+
await this.#flushOtherChannels(channel);
|
|
147
|
+
entry.refCount += 1;
|
|
148
|
+
this.#log('WS subscription still alive, bumped refCount', {
|
|
149
|
+
channel,
|
|
150
|
+
refCount: entry.refCount,
|
|
151
|
+
});
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// WS subscription was lost (e.g. after disconnect/reconnect) — fall
|
|
155
|
+
// through to recreate it. refCount is bumped only after success below.
|
|
156
|
+
}
|
|
157
|
+
else if (entry && entry.refCount > 0) {
|
|
158
|
+
entry.refCount += 1;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
await this.#flushOtherChannels(channel);
|
|
162
|
+
try {
|
|
163
|
+
await this.#messenger.call('BackendWebSocketService:connect');
|
|
164
|
+
if (this.#messenger.call('BackendWebSocketService:channelHasSubscription', channel)) {
|
|
165
|
+
this.#log('Channel already has WS subscription (idempotency), skipping', {
|
|
166
|
+
channel,
|
|
167
|
+
});
|
|
168
|
+
this.#channels.set(channel, { refCount: 1 });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await this.#messenger.call('BackendWebSocketService:subscribe', {
|
|
172
|
+
channels: [channel],
|
|
173
|
+
channelType: this.#channelType,
|
|
174
|
+
callback: (notification) => {
|
|
175
|
+
this.#options.onMessage(channel, notification);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
this.#channels.set(channel, { refCount: 1 });
|
|
179
|
+
this.#log('Subscribe succeeded — new WS subscription created', {
|
|
180
|
+
channel,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
this.#log('Subscription failed', { channel, error });
|
|
185
|
+
this.#channels.delete(channel);
|
|
186
|
+
this.#options.onSubscriptionError?.(channel, String(error), 'subscribe');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Unsubscribe from a channel. Decrements the reference count and, when it
|
|
191
|
+
* reaches zero, starts a grace-period timer before actually unsubscribing from
|
|
192
|
+
* the WebSocket to absorb rapid navigation patterns.
|
|
193
|
+
*
|
|
194
|
+
* @param channel - The fully-qualified channel name.
|
|
195
|
+
* @returns A promise that resolves once the unsubscription is processed.
|
|
196
|
+
*/
|
|
197
|
+
async unsubscribe(channel) {
|
|
198
|
+
const releaseLock = await this.#mutex.acquire();
|
|
199
|
+
try {
|
|
200
|
+
await this.#unsubscribeInner(channel);
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
releaseLock();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async #unsubscribeInner(channel) {
|
|
207
|
+
const entry = this.#channels.get(channel);
|
|
208
|
+
if (!entry || entry.refCount <= 0) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
entry.refCount -= 1;
|
|
212
|
+
if (entry.refCount > 0) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
entry.gracePeriodTimer = setTimeout(() => {
|
|
216
|
+
entry.gracePeriodTimer = undefined;
|
|
217
|
+
this.#performUnsubscribe(channel).catch(() => {
|
|
218
|
+
// no-op: retry scheduling and force-reconnection are handled internally
|
|
219
|
+
});
|
|
220
|
+
}, this.#gracePeriodMs);
|
|
221
|
+
}
|
|
222
|
+
// =============================================================================
|
|
223
|
+
// Private — WebSocket Subscription Helpers
|
|
224
|
+
// =============================================================================
|
|
225
|
+
/**
|
|
226
|
+
* Immediately unsubscribe other channels in grace or failed-cleanup state.
|
|
227
|
+
* Called while the subscribe mutex is held before opening a new channel.
|
|
228
|
+
*
|
|
229
|
+
* @param exceptChannel - Channel being subscribed; excluded from flush.
|
|
230
|
+
*/
|
|
231
|
+
async #flushOtherChannels(exceptChannel) {
|
|
232
|
+
for (const [channel, channelEntry] of this.#channels.entries()) {
|
|
233
|
+
if (channel === exceptChannel || channelEntry.refCount > 0) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
this.#clearChannelTimers(channelEntry);
|
|
237
|
+
this.#log('Flushing grace-period channel before new subscribe', {
|
|
238
|
+
flushedChannel: channel,
|
|
239
|
+
newChannel: exceptChannel,
|
|
240
|
+
});
|
|
241
|
+
const success = await this.#unsubscribeChannelOnServer(channel);
|
|
242
|
+
if (success) {
|
|
243
|
+
this.#channels.delete(channel);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
this.#scheduleUnsubscribeRetry(channel);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
#clearChannelTimers(entry) {
|
|
251
|
+
if (entry.gracePeriodTimer) {
|
|
252
|
+
clearTimeout(entry.gracePeriodTimer);
|
|
253
|
+
entry.gracePeriodTimer = undefined;
|
|
254
|
+
}
|
|
255
|
+
entry.retryAbort?.abort();
|
|
256
|
+
entry.retryAbort = undefined;
|
|
257
|
+
}
|
|
258
|
+
async #unsubscribeChannelOnServer(channel) {
|
|
259
|
+
try {
|
|
260
|
+
const subscriptions = this.#messenger.call('BackendWebSocketService:getSubscriptionsByChannel', channel);
|
|
261
|
+
for (const sub of subscriptions) {
|
|
262
|
+
await sub.unsubscribe();
|
|
263
|
+
}
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
this.#log('Unsubscription failed', { channel, error });
|
|
268
|
+
this.#options.onSubscriptionError?.(channel, String(error), 'unsubscribe');
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
#scheduleUnsubscribeRetry(channel) {
|
|
273
|
+
const entry = this.#channels.get(channel);
|
|
274
|
+
if (!entry) {
|
|
275
|
+
// The channel was removed (e.g. destroy() or reconnect cleanup) while the
|
|
276
|
+
// unsubscribe was in flight. Do not resurrect it or start a new retry loop
|
|
277
|
+
// with an AbortController that teardown can no longer cancel — that could
|
|
278
|
+
// force a reconnection on the shared WebSocket after teardown.
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
entry.retryAbort?.abort();
|
|
282
|
+
entry.retryAbort = new AbortController();
|
|
283
|
+
const { signal } = entry.retryAbort;
|
|
284
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
285
|
+
this.#runUnsubRetryLoop(channel, signal);
|
|
286
|
+
}
|
|
287
|
+
async #runUnsubRetryLoop(channel, signal) {
|
|
288
|
+
try {
|
|
289
|
+
await this.#unsubRetryPolicy.execute(async () => {
|
|
290
|
+
const releaseLock = await this.#mutex.acquire();
|
|
291
|
+
try {
|
|
292
|
+
const current = this.#channels.get(channel);
|
|
293
|
+
if (current && current.refCount > 0) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const success = await this.#unsubscribeChannelOnServer(channel);
|
|
297
|
+
if (!success) {
|
|
298
|
+
throw new Error('unsubscribe failed');
|
|
299
|
+
}
|
|
300
|
+
this.#channels.delete(channel);
|
|
301
|
+
this.#log('WS unsubscribe completed', { channel });
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
releaseLock();
|
|
305
|
+
}
|
|
306
|
+
}, signal);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
if (signal.aborted) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
this.#log('Unsubscribe retries exhausted — forcing reconnection', {
|
|
313
|
+
channel,
|
|
314
|
+
});
|
|
315
|
+
this.#channels.delete(channel);
|
|
316
|
+
// Last resort: reconnects the shared BackendWebSocketService instance
|
|
317
|
+
// (other consumers share this connection). They resubscribe on CONNECTED;
|
|
318
|
+
// this manager only resubscribes channels with refCount > 0.
|
|
319
|
+
await this.#messenger
|
|
320
|
+
.call('BackendWebSocketService:forceReconnection')
|
|
321
|
+
.catch(() => {
|
|
322
|
+
// no-op
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async #performUnsubscribe(channel) {
|
|
327
|
+
const releaseLock = await this.#mutex.acquire();
|
|
328
|
+
try {
|
|
329
|
+
const entry = this.#channels.get(channel);
|
|
330
|
+
if (entry && entry.refCount > 0) {
|
|
331
|
+
this.#log('Skipping unsubscribe — new subscriber arrived while queued', { channel, refCount: entry.refCount });
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
this.#log('Grace period expired — performing actual WS unsubscribe', {
|
|
335
|
+
channel,
|
|
336
|
+
});
|
|
337
|
+
this.#clearChannelTimers(this.#channels.get(channel) ?? { refCount: 0 });
|
|
338
|
+
}
|
|
339
|
+
finally {
|
|
340
|
+
releaseLock();
|
|
341
|
+
}
|
|
342
|
+
this.#scheduleUnsubscribeRetry(channel);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Resubscribe all channels that were active before a disconnect.
|
|
346
|
+
* Called when WebSocket transitions to CONNECTED.
|
|
347
|
+
*/
|
|
348
|
+
async #resubscribeActiveChannels() {
|
|
349
|
+
const releaseLock = await this.#mutex.acquire();
|
|
350
|
+
try {
|
|
351
|
+
const channelCount = this.#channels.size;
|
|
352
|
+
this.#log('Resubscribing active channels after reconnect', {
|
|
353
|
+
count: channelCount,
|
|
354
|
+
});
|
|
355
|
+
for (const [channel, entry] of [...this.#channels.entries()]) {
|
|
356
|
+
if (entry.refCount === 0) {
|
|
357
|
+
this.#clearChannelTimers(entry);
|
|
358
|
+
this.#channels.delete(channel);
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
if (this.#messenger.call('BackendWebSocketService:channelHasSubscription', channel)) {
|
|
363
|
+
this.#log('Channel already subscribed on server, skipping resubscribe', {
|
|
364
|
+
channel,
|
|
365
|
+
});
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
await this.#messenger.call('BackendWebSocketService:subscribe', {
|
|
369
|
+
channels: [channel],
|
|
370
|
+
channelType: this.#channelType,
|
|
371
|
+
callback: (notification) => {
|
|
372
|
+
this.#options.onMessage(channel, notification);
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
this.#log('Resubscription succeeded', { channel });
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
this.#log('Resubscription failed for channel', {
|
|
379
|
+
channel,
|
|
380
|
+
error,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
finally {
|
|
386
|
+
releaseLock();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async #handleWebSocketStateChange(connectionInfo) {
|
|
390
|
+
if (connectionInfo.state === WebSocketState.CONNECTED) {
|
|
391
|
+
await this.#resubscribeActiveChannels();
|
|
392
|
+
}
|
|
393
|
+
this.#options.onConnectionStateChange?.(connectionInfo);
|
|
394
|
+
}
|
|
395
|
+
// =============================================================================
|
|
396
|
+
// Public — Cleanup
|
|
397
|
+
// =============================================================================
|
|
398
|
+
/**
|
|
399
|
+
* Tear down all channel timers and, if configured, remove the
|
|
400
|
+
* system-notifications channel callback.
|
|
401
|
+
*/
|
|
402
|
+
destroy() {
|
|
403
|
+
for (const entry of this.#channels.values()) {
|
|
404
|
+
this.#clearChannelTimers(entry);
|
|
405
|
+
}
|
|
406
|
+
this.#channels.clear();
|
|
407
|
+
const { systemNotificationsChannel } = this.#options;
|
|
408
|
+
if (systemNotificationsChannel) {
|
|
409
|
+
this.#messenger.call('BackendWebSocketService:removeChannelCallback', systemNotificationsChannel);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
//# sourceMappingURL=ChannelSubscriptionManager.js.map
|