@polyester/sdk 0.24.0 → 0.24.1

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @polyester/sdk
2
2
 
3
+ ## 0.24.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Notify consumers of terminal realtime server disconnects and unsubscribes with their code and reason, and remove stopped channels from active tracking. ([#148](https://github.com/Fabric-Labs/polyester-sdk-typescript/pull/148))
8
+
9
+ - Read the current JWT provider value for every realtime token request so additional subscribers cannot retain stale credentials after token rotation or logout. ([#149](https://github.com/Fabric-Labs/polyester-sdk-typescript/pull/149))
10
+
11
+ - Declare the account signer's `ownerAddress` (the connected EOA) as the LOGIN challenge `signerAddress` instead of the Safe `accountAddress`, so wallet login and session refresh authenticate a Safe smart account with a distinct EOA signer. Subaccount creation challenges are unchanged. ([#151](https://github.com/Fabric-Labs/polyester-sdk-typescript/pull/151))
12
+
3
13
  ## 0.24.0
4
14
 
5
15
  ### Minor Changes
@@ -12,7 +12,7 @@ interface AccountSigner {
12
12
  readonly environmentFingerprint: string;
13
13
  /** The smart account address (used for authentication and trading) */
14
14
  readonly accountAddress: HexAddress;
15
- /** The owner/EOA address (optional metadata about the controlling signer) */
15
+ /** The owner/EOA address. Declared as the LOGIN challenge signer when present; otherwise accountAddress signs. */
16
16
  readonly ownerAddress?: HexAddress;
17
17
  /** Sign the exact UTF-8 message with EIP-191 semantics for accountAddress (including smart-account wrapping when required). */
18
18
  signMessage(message: string): Promise<Hex>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/account-signer/types.ts"],"sourcesContent":["import type { Hex } from \"viem\";\nimport { isEvmAddress } from \"../utils/evm.js\";\nimport { ConfigurationError } from \"../shared/errors.js\";\n\nexport type HexAddress = `0x${string}`;\n\n/**\n * Minimal account signer interface for SDK operations.\n *\n * The SDK authenticates the Polyester smart account address. The owner address\n * is optional metadata about the EOA or custody provider that controls it.\n */\nexport interface AccountSigner {\n /** Fingerprint of the PolyesterEnvironment this signer was created for */\n readonly environmentFingerprint: string;\n\n /** The smart account address (used for authentication and trading) */\n readonly accountAddress: HexAddress;\n\n /** The owner/EOA address (optional metadata about the controlling signer) */\n readonly ownerAddress?: HexAddress;\n\n /** Sign the exact UTF-8 message with EIP-191 semantics for accountAddress (including smart-account wrapping when required). */\n signMessage(message: string): Promise<Hex>;\n}\n\n/**\n * Factory function type for lazy account signer initialization.\n * Useful when the signer might not be available at client creation time.\n */\nexport type AccountSignerFactory = () => AccountSigner | null | Promise<AccountSigner | null>;\n\n/**\n * Account signer configuration for the client.\n * Can be a signer instance or a factory for lazy initialization.\n */\nexport type AccountSignerConfig = AccountSigner | AccountSignerFactory;\n\n/**\n * Helper to check if an account signer config is a factory function.\n */\nexport function isAccountSignerFactory(\n config: AccountSignerConfig,\n): config is AccountSignerFactory {\n return typeof config === \"function\";\n}\n\n/**\n * Asserts that a value implements the account signer contract.\n */\nexport function assertAccountSigner(value: AccountSigner): void {\n if (typeof value !== \"object\" || value === null) {\n throw new ConfigurationError(\"Account signer must be an object or factory function.\");\n }\n if (!value.environmentFingerprint) {\n throw new ConfigurationError(\"Account signer must include an environmentFingerprint.\");\n }\n if (!isEvmAddress(value.accountAddress)) {\n throw new ConfigurationError(\"Account signer must include a valid accountAddress.\");\n }\n if (value.ownerAddress && !isEvmAddress(value.ownerAddress)) {\n throw new ConfigurationError(\"Account signer ownerAddress must be a valid address.\");\n }\n if (typeof value.signMessage !== \"function\") {\n throw new ConfigurationError(\"Account signer must include a signMessage function.\");\n }\n}\n\n/**\n * Helper to resolve an account signer from config.\n */\nexport async function resolveAccountSigner(\n config: AccountSignerConfig | undefined,\n): Promise<AccountSigner | null> {\n if (!config) return null;\n const accountSigner = isAccountSignerFactory(config) ? await config() : config;\n if (accountSigner) assertAccountSigner(accountSigner);\n return accountSigner;\n}\n"],"mappings":";;;;;;AAyCA,SAAgB,uBACZ,QAC8B;CAC9B,OAAO,OAAO,WAAW;AAC7B;;;;AAKA,SAAgB,oBAAoB,OAA4B;CAC5D,IAAI,OAAO,UAAU,YAAY,UAAU,MACvC,MAAM,IAAI,mBAAmB,uDAAuD;CAExF,IAAI,CAAC,MAAM,wBACP,MAAM,IAAI,mBAAmB,wDAAwD;CAEzF,IAAI,CAAC,aAAa,MAAM,cAAc,GAClC,MAAM,IAAI,mBAAmB,qDAAqD;CAEtF,IAAI,MAAM,gBAAgB,CAAC,aAAa,MAAM,YAAY,GACtD,MAAM,IAAI,mBAAmB,sDAAsD;CAEvF,IAAI,OAAO,MAAM,gBAAgB,YAC7B,MAAM,IAAI,mBAAmB,qDAAqD;AAE1F;;;;AAKA,eAAsB,qBAClB,QAC6B;CAC7B,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,gBAAgB,uBAAuB,MAAM,IAAI,MAAM,OAAO,IAAI;CACxE,IAAI,eAAe,oBAAoB,aAAa;CACpD,OAAO;AACX"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/account-signer/types.ts"],"sourcesContent":["import type { Hex } from \"viem\";\nimport { isEvmAddress } from \"../utils/evm.js\";\nimport { ConfigurationError } from \"../shared/errors.js\";\n\nexport type HexAddress = `0x${string}`;\n\n/**\n * Minimal account signer interface for SDK operations.\n *\n * The SDK authenticates the Polyester smart account address. The owner address\n * is optional metadata about the EOA or custody provider that controls it.\n */\nexport interface AccountSigner {\n /** Fingerprint of the PolyesterEnvironment this signer was created for */\n readonly environmentFingerprint: string;\n\n /** The smart account address (used for authentication and trading) */\n readonly accountAddress: HexAddress;\n\n /** The owner/EOA address. Declared as the LOGIN challenge signer when present; otherwise accountAddress signs. */\n readonly ownerAddress?: HexAddress;\n\n /** Sign the exact UTF-8 message with EIP-191 semantics for accountAddress (including smart-account wrapping when required). */\n signMessage(message: string): Promise<Hex>;\n}\n\n/**\n * Factory function type for lazy account signer initialization.\n * Useful when the signer might not be available at client creation time.\n */\nexport type AccountSignerFactory = () => AccountSigner | null | Promise<AccountSigner | null>;\n\n/**\n * Account signer configuration for the client.\n * Can be a signer instance or a factory for lazy initialization.\n */\nexport type AccountSignerConfig = AccountSigner | AccountSignerFactory;\n\n/**\n * Helper to check if an account signer config is a factory function.\n */\nexport function isAccountSignerFactory(\n config: AccountSignerConfig,\n): config is AccountSignerFactory {\n return typeof config === \"function\";\n}\n\n/**\n * Asserts that a value implements the account signer contract.\n */\nexport function assertAccountSigner(value: AccountSigner): void {\n if (typeof value !== \"object\" || value === null) {\n throw new ConfigurationError(\"Account signer must be an object or factory function.\");\n }\n if (!value.environmentFingerprint) {\n throw new ConfigurationError(\"Account signer must include an environmentFingerprint.\");\n }\n if (!isEvmAddress(value.accountAddress)) {\n throw new ConfigurationError(\"Account signer must include a valid accountAddress.\");\n }\n if (value.ownerAddress && !isEvmAddress(value.ownerAddress)) {\n throw new ConfigurationError(\"Account signer ownerAddress must be a valid address.\");\n }\n if (typeof value.signMessage !== \"function\") {\n throw new ConfigurationError(\"Account signer must include a signMessage function.\");\n }\n}\n\n/**\n * Helper to resolve an account signer from config.\n */\nexport async function resolveAccountSigner(\n config: AccountSignerConfig | undefined,\n): Promise<AccountSigner | null> {\n if (!config) return null;\n const accountSigner = isAccountSignerFactory(config) ? await config() : config;\n if (accountSigner) assertAccountSigner(accountSigner);\n return accountSigner;\n}\n"],"mappings":";;;;;;AAyCA,SAAgB,uBACZ,QAC8B;CAC9B,OAAO,OAAO,WAAW;AAC7B;;;;AAKA,SAAgB,oBAAoB,OAA4B;CAC5D,IAAI,OAAO,UAAU,YAAY,UAAU,MACvC,MAAM,IAAI,mBAAmB,uDAAuD;CAExF,IAAI,CAAC,MAAM,wBACP,MAAM,IAAI,mBAAmB,wDAAwD;CAEzF,IAAI,CAAC,aAAa,MAAM,cAAc,GAClC,MAAM,IAAI,mBAAmB,qDAAqD;CAEtF,IAAI,MAAM,gBAAgB,CAAC,aAAa,MAAM,YAAY,GACtD,MAAM,IAAI,mBAAmB,sDAAsD;CAEvF,IAAI,OAAO,MAAM,gBAAgB,YAC7B,MAAM,IAAI,mBAAmB,qDAAqD;AAE1F;;;;AAKA,eAAsB,qBAClB,QAC6B;CAC7B,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,gBAAgB,uBAAuB,MAAM,IAAI,MAAM,OAAO,IAAI;CACxE,IAAI,eAAe,oBAAoB,aAAa;CACpD,OAAO;AACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"core-client.d.ts","names":[],"sources":["../src/core-client.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkHY,8BAA8B,KAAK;UAErC;EACN,aAAa;EACb,eAAe;EACf,OAAO,kBAAkB;EACzB,WAAW;;;;;EAKX;;;;;;;EAOA,aAAa;;;;;;EAMb,iBAAiB;;KAGhB;;EAGK,SAAS;EACT;EACA;;EAGA;;;;;;EAMA,kBAAkB;;;;;EAKlB,cAAc;;;KAIZ,4BAA4B,8BAA8B;;KAG1D,wBAAwB;UAc1B;EACN,YAAY;EACZ,UAAU;EACV,aAAa;EACb,aAAa;;UAGP;EACN,cAAc,SAAS,8BAA8B;;;;;;;;;cAqC5C;;qBACU,YAAY;EA8CnB,YAAA,QAAQ,uBAAuB,UAAS;MAyBhD,YAAY;MAoBZ,WAAW;MAwCX,QAAQ;MAaR,YAAY;MAIZ,WAAW;MAQX,eAAe;MAQf,WAAW;MAQX,kBAAkB;MAOlB,cAAc;MAQd,kBAAkB;MAQlB,aAAa;MAQb,WAAW;MAQX,aAAa;MAIb,UAAU;MASV,UAAU;MASV,YAAY;MASZ,YAAY;MASZ,aAAa;MAQb,qBAAqB;MAQrB,oBAAoB;MAapB,WAAW;MAIX,eAAe;MAQf,eAAe;MAIf,sBAAsB;MAItB,cAAc;MAId,UAAU;MAQV,OAAO;MAIP,OAAO;MAIP,QAAQ;MAIR,qBAAqB;;;;;YAWf,4BAA4B"}
1
+ {"version":3,"file":"core-client.d.ts","names":[],"sources":["../src/core-client.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwFY,8BAA8B,KAAK;UAErC;EACN,aAAa;EACb,eAAe;EACf,OAAO,kBAAkB;EACzB,WAAW;;;;;EAKX;;;;;;;EAOA,aAAa;;;;;;EAMb,iBAAiB;;KAGhB;;EAGK,SAAS;EACT;EACA;;EAGA;;;;;;EAMA,kBAAkB;;;;;EAKlB,cAAc;;;KAIZ,4BAA4B,8BAA8B;;KAG1D,wBAAwB;UAc1B;EACN,YAAY;EACZ,UAAU;EACV,aAAa;EACb,aAAa;;UAGP;EACN,cAAc,SAAS,8BAA8B;;;;;;;;;cAqC5C;;qBACU,YAAY;EA8CnB,YAAA,QAAQ,uBAAuB,UAAS;MAyBhD,YAAY;MAoBZ,WAAW;MAwCX,QAAQ;MAaR,YAAY;MAIZ,WAAW;MAQX,eAAe;MAQf,WAAW;MAQX,kBAAkB;MAOlB,cAAc;MAQd,kBAAkB;MAQlB,aAAa;MAQb,WAAW;MAQX,aAAa;MAIb,UAAU;MASV,UAAU;MASV,YAAY;MASZ,YAAY;MASZ,aAAa;MAQb,qBAAqB;MAQrB,oBAAoB;MAapB,WAAW;MAIX,eAAe;MAQf,eAAe;MAIf,sBAAsB;MAItB,cAAc;MAId,UAAU;MAQV,OAAO;MAIP,OAAO;MAIP,QAAQ;MAIR,qBAAqB;;;;;YAWf,4BAA4B"}
@@ -35,53 +35,26 @@ import { RealtimeClient } from "./realtime/client.js";
35
35
  //#region src/core-client.ts
36
36
  function realtimeAuthFromProvider(auth) {
37
37
  if (!auth) return {};
38
- if (auth.kind === "jwt") {
39
- let cachedTokenResolution;
40
- const prefetchToken = () => {
41
- if (cachedTokenResolution) return cachedTokenResolution;
38
+ if (auth.kind === "jwt") return {
39
+ getAuthHeaders: async () => {
40
+ const token = await resolveJwtToken(auth);
41
+ const headers = {};
42
+ if (token) headers.authorization = `Bearer ${token}`;
43
+ return headers;
44
+ },
45
+ hasAuth: () => {
42
46
  try {
43
- const value = auth.getToken();
44
- if (value !== null && typeof value !== "string") value.catch(() => {});
45
- cachedTokenResolution = {
46
- kind: "value",
47
- value
48
- };
49
- } catch (cause) {
50
- cachedTokenResolution = {
51
- kind: "error",
52
- cause
53
- };
54
- }
55
- return cachedTokenResolution;
56
- };
57
- const consumeToken = () => {
58
- const resolution = cachedTokenResolution;
59
- cachedTokenResolution = void 0;
60
- if (!resolution) return auth.getToken();
61
- if (resolution.kind === "error") throw resolution.cause;
62
- return resolution.value;
63
- };
64
- const cachedAuth = {
65
- kind: "jwt",
66
- getToken: consumeToken
67
- };
68
- return {
69
- getAuthHeaders: async () => {
70
- const token = await resolveJwtToken(cachedAuth);
71
- const headers = {};
72
- if (token) headers.authorization = `Bearer ${token}`;
73
- return headers;
74
- },
75
- hasAuth: () => {
76
- const resolution = prefetchToken();
77
- if (resolution.kind === "error") return true;
78
- if (resolution.value !== null && typeof resolution.value !== "string") return true;
79
- const hasToken = resolution.value !== null && resolution.value.length > 0;
80
- if (!hasToken) cachedTokenResolution = void 0;
81
- return hasToken;
47
+ const token = auth.getToken();
48
+ if (token !== null && typeof token !== "string") {
49
+ token.catch(() => {});
50
+ return true;
51
+ }
52
+ return token !== null && token.length > 0;
53
+ } catch {
54
+ return true;
82
55
  }
83
- };
84
- }
56
+ }
57
+ };
85
58
  return {
86
59
  getAuthHeaders: (request) => createApiKeyEd25519AuthHeaders(auth, {
87
60
  url: request.url,
@@ -1 +1 @@
1
- {"version":3,"file":"core-client.js","names":["#environment","#authProvider","#realtimeConfig","#configRealtimeClient","#configCatalog","#configCatalogSnapshot","#configCatalogCell","#createAuth","#realtime","#catalog","#getScales","#scales","#resolverInitialized","#resolver","#auth","#accounts","#apiKeys","#getResolver","#subaccounts","#candles","#chainAnalytics","#marketData","#marketOverview","#orderbook","#heatmap","#lifecycle","#trades","#orders","#triggers","#balances","#transfers","#internalTransfers","#tradingWithdraws","#deposit","#addressBook","#guardSigner","#socialVerification","#whiteboard","#zipper","#mfa","#vip","#fees","#tradingRateLimits"],"sources":["../src/core-client.ts"],"sourcesContent":["import type { Interceptor } from \"@connectrpc/connect\";\nimport { ConfigurationError } from \"./shared/errors.js\";\nimport {\n createApiKeyEd25519AuthHeaders,\n createTransports,\n resolveJwtToken,\n type AuthAndPublicApiTransports,\n type Transports,\n type JwtAuthProvider,\n type ApiKeyEd25519AuthProvider,\n} from \"./shared/transports.js\";\nimport { parsePolyesterEnvironment, type PolyesterEnvironment } from \"./environment.js\";\nimport { AccountsService } from \"./services/accounts/index.js\";\nimport { ApiKeysService } from \"./services/api-keys/index.js\";\nimport { AuthService } from \"./services/auth/auth.js\";\nimport { SubaccountsService } from \"./services/subaccounts/index.js\";\nimport { CandlesService } from \"./services/candles/index.js\";\nimport { ChainAnalyticsService } from \"./services/chain-analytics/index.js\";\nimport { MarketDataService } from \"./services/market-data/index.js\";\nimport { MarketOverviewService } from \"./services/market-overview/index.js\";\nimport { OrderbookService } from \"./services/orderbook/index.js\";\nimport { HeatmapService } from \"./services/heatmap/index.js\";\nimport { LifecycleService } from \"./services/lifecycle/index.js\";\nimport { TradesService } from \"./services/trades/index.js\";\nimport { OrdersService } from \"./services/orders/index.js\";\nimport { TriggersService } from \"./services/triggers/index.js\";\nimport { BalancesService } from \"./services/balances/index.js\";\nimport { TransfersService } from \"./services/transfers/index.js\";\nimport { InternalTransfersService } from \"./services/internal-transfers/index.js\";\nimport { TradingWithdrawsService } from \"./services/trading-withdraws/index.js\";\nimport { DepositService } from \"./services/deposit/index.js\";\nimport { AddressBookService } from \"./services/address-book/index.js\";\nimport { GuardSignerService } from \"./services/guard-signer/index.js\";\nimport { SocialVerificationService } from \"./services/social-verification/index.js\";\nimport { WhiteboardService } from \"./services/whiteboard/index.js\";\nimport { ZipperService } from \"./services/zipper/index.js\";\nimport { MfaService } from \"./services/mfa/index.js\";\nimport { VipService } from \"./services/vip/index.js\";\nimport { FeesService } from \"./services/fees/index.js\";\nimport { RateLimitService } from \"./services/rate-limits/index.js\";\nimport type { SubaccountResolver } from \"./services/subaccount-resolver.js\";\nimport {\n createPolyesterCatalog,\n type CatalogSnapshot,\n type CatalogSnapshotCell,\n type ClientCatalog,\n} from \"./catalogs/index.js\";\nimport { createCatalogSdkScales, type SdkScales } from \"./shared/decimal-surface.js\";\nimport { RealtimeClient, type PolyesterRealtime, type RealtimeConfig } from \"./realtime/index.js\";\n\nfunction realtimeAuthFromProvider(\n auth: JwtAuthProvider | ApiKeyEd25519AuthProvider | undefined,\n): Pick<RealtimeConfig, \"getAuthHeaders\" | \"hasAuth\"> {\n if (!auth) return {};\n if (auth.kind === \"jwt\") {\n type CachedTokenResolution =\n | { kind: \"value\"; value: ReturnType<JwtAuthProvider[\"getToken\"]> }\n | { kind: \"error\"; cause: unknown };\n\n let cachedTokenResolution: CachedTokenResolution | undefined;\n\n const prefetchToken = (): CachedTokenResolution => {\n if (cachedTokenResolution) return cachedTokenResolution;\n\n try {\n const value = auth.getToken();\n // Async providers cannot be preflighted synchronously. Attach a\n // rejection observer while the credential waits for the request.\n if (value !== null && typeof value !== \"string\") void value.catch(() => {});\n cachedTokenResolution = { kind: \"value\", value };\n } catch (cause) {\n cachedTokenResolution = { kind: \"error\", cause };\n }\n return cachedTokenResolution;\n };\n\n const consumeToken = (): ReturnType<JwtAuthProvider[\"getToken\"]> => {\n const resolution = cachedTokenResolution;\n cachedTokenResolution = undefined;\n\n if (!resolution) return auth.getToken();\n if (resolution.kind === \"error\") throw resolution.cause;\n return resolution.value;\n };\n const cachedAuth = { kind: \"jwt\", getToken: consumeToken } satisfies JwtAuthProvider;\n\n return {\n getAuthHeaders: async () => {\n const token = await resolveJwtToken(cachedAuth);\n const headers: Record<string, string> = {};\n if (token) headers.authorization = `Bearer ${token}`;\n return headers;\n },\n hasAuth: () => {\n const resolution = prefetchToken();\n if (resolution.kind === \"error\") return true;\n if (resolution.value !== null && typeof resolution.value !== \"string\") return true;\n\n const hasToken = resolution.value !== null && resolution.value.length > 0;\n if (!hasToken) cachedTokenResolution = undefined;\n return hasToken;\n },\n };\n }\n return {\n getAuthHeaders: (request) =>\n createApiKeyEd25519AuthHeaders(auth, {\n url: request.url,\n method: request.method,\n }),\n hasAuth: () => true,\n };\n}\n\nexport type PolyesterRealtimeAuthConfig = Pick<RealtimeConfig, \"getAuthHeaders\" | \"hasAuth\">;\n\ninterface PolyesterClientCommonConfig {\n environment: PolyesterEnvironment;\n interceptors?: Interceptor[];\n auth?: JwtAuthProvider | ApiKeyEd25519AuthProvider;\n realtime?: PolyesterRealtimeAuthConfig;\n /**\n * Connect wire format. Defaults to binary for production performance.\n * Use `json` for human-readable debugging.\n */\n wireFormat?: \"binary\" | \"json\";\n /**\n * Advanced: inject pre-built Connect transports (in-memory mocks, custom\n * stacks). When provided, the SDK does not build its own transports and the\n * built-in auth/error-mapping interceptors are NOT applied — the injected\n * transports own their full interceptor chain.\n */\n transports?: Transports;\n /**\n * Advanced: inject a realtime implementation (in-memory mocks, custom\n * stacks). When provided, the SDK skips constructing its Centrifuge-backed\n * realtime client and the `realtime` auth config is ignored.\n */\n realtimeClient?: PolyesterRealtime;\n}\n\ntype PolyesterCatalogConfig =\n | {\n /** Client-owned catalog store. */\n catalog: ClientCatalog;\n catalogSnapshot?: never;\n catalogCell?: never;\n }\n | {\n catalog?: never;\n /**\n * Explicit initial catalog snapshot, commonly hydrated from server-rendered data.\n * Combines with `catalogCell` as the cell's initial value without clobbering a\n * pre-populated cell.\n */\n catalogSnapshot?: CatalogSnapshot;\n /**\n * External snapshot storage for the client-built catalog. A cell backed by a\n * reactive source makes every catalog read reactive.\n */\n catalogCell?: CatalogSnapshotCell;\n };\n\n/** Configuration shared by every Polyester client. */\nexport type PolyesterClientBaseConfig = PolyesterClientCommonConfig & PolyesterCatalogConfig;\n\n/** Configuration for the base Polyester client. */\nexport type PolyesterClientConfig = PolyesterClientBaseConfig;\n\n/** Preserves the exclusive catalog configuration while projecting client config fields. */\nexport function pickPolyesterCatalogConfig(\n config: PolyesterClientBaseConfig,\n): PolyesterCatalogConfig {\n return config.catalog === undefined\n ? {\n catalogSnapshot: config.catalogSnapshot,\n catalogCell: config.catalogCell,\n }\n : { catalog: config.catalog };\n}\n\ninterface AuthServiceFactoryContext {\n transports: AuthAndPublicApiTransports;\n realtime: PolyesterRealtime;\n subaccounts: SubaccountsService;\n environment: PolyesterEnvironment;\n}\n\ninterface PolyesterClientRuntimeConfig {\n createAuth?: (context: AuthServiceFactoryContext) => AuthService;\n}\n\n/**\n * Parses the configuration shared by every public client constructor.\n */\nexport function parsePolyesterClientConfig<TConfig extends PolyesterClientBaseConfig>(\n config: TConfig,\n): TConfig {\n if (typeof config !== \"object\" || config === null || Array.isArray(config)) {\n throw new ConfigurationError(\"Client configuration must be an object.\");\n }\n const environment = parsePolyesterEnvironment(config.environment);\n if (\n config.wireFormat !== undefined &&\n config.wireFormat !== \"binary\" &&\n config.wireFormat !== \"json\"\n ) {\n throw new ConfigurationError('wireFormat must be either \"binary\" or \"json\".');\n }\n if (config.catalog && config.catalogSnapshot) {\n throw new ConfigurationError(\"Provide either catalog or catalogSnapshot, not both.\");\n }\n if (config.catalog && config.catalogCell) {\n throw new ConfigurationError(\"Provide either catalog or catalogCell, not both.\");\n }\n\n return Object.assign({}, config, { environment });\n}\n\n/**\n * Base SDK client that wires transports, realtime, catalogs, and all public service clients for a Polyester environment.\n *\n * Services are constructed lazily on first property access (and memoized) so\n * that creating a client — which happens for every SSR request in server\n * hooks — only pays for the services the caller actually touches.\n */\nexport class PolyesterClient {\n protected readonly transports: Transports;\n\n readonly #environment: PolyesterEnvironment;\n readonly #authProvider: JwtAuthProvider | ApiKeyEd25519AuthProvider | undefined;\n readonly #realtimeConfig: PolyesterRealtimeAuthConfig | undefined;\n readonly #configRealtimeClient: PolyesterRealtime | undefined;\n readonly #configCatalog: ClientCatalog | undefined;\n readonly #configCatalogSnapshot: CatalogSnapshot | undefined;\n readonly #configCatalogCell: CatalogSnapshotCell | undefined;\n readonly #createAuth: PolyesterClientRuntimeConfig[\"createAuth\"];\n\n #realtime: PolyesterRealtime | undefined;\n #catalog: ClientCatalog | undefined;\n #scales: SdkScales | undefined;\n #resolver: SubaccountResolver | undefined;\n #resolverInitialized = false;\n\n #auth: AuthService | undefined;\n #accounts: AccountsService | undefined;\n #apiKeys: ApiKeysService | undefined;\n #subaccounts: SubaccountsService | undefined;\n #candles: CandlesService | undefined;\n #chainAnalytics: ChainAnalyticsService | undefined;\n #marketData: MarketDataService | undefined;\n #marketOverview: MarketOverviewService | undefined;\n #orderbook: OrderbookService | undefined;\n #heatmap: HeatmapService | undefined;\n #lifecycle: LifecycleService | undefined;\n #trades: TradesService | undefined;\n #orders: OrdersService | undefined;\n #triggers: TriggersService | undefined;\n #balances: BalancesService | undefined;\n #transfers: TransfersService | undefined;\n #internalTransfers: InternalTransfersService | undefined;\n #tradingWithdraws: TradingWithdrawsService | undefined;\n #deposit: DepositService | undefined;\n #addressBook: AddressBookService | undefined;\n #guardSigner: GuardSignerService | undefined;\n #socialVerification: SocialVerificationService | undefined;\n #whiteboard: WhiteboardService | undefined;\n #zipper: ZipperService | undefined;\n #mfa: MfaService | undefined;\n #vip: VipService | undefined;\n #fees: FeesService | undefined;\n #tradingRateLimits: RateLimitService | undefined;\n\n constructor(config: PolyesterClientConfig, runtime: PolyesterClientRuntimeConfig = {}) {\n const parsedConfig = parsePolyesterClientConfig(config);\n config = parsedConfig;\n const interceptors = config.interceptors ?? [];\n const { environment } = config;\n\n this.transports =\n config.transports ??\n createTransports({\n apiUrl: environment.apiUrl,\n interceptors,\n auth: config.auth,\n wireFormat: config.wireFormat,\n });\n\n this.#environment = environment;\n this.#authProvider = config.auth;\n this.#realtimeConfig = config.realtime;\n this.#configRealtimeClient = config.realtimeClient;\n this.#configCatalog = config.catalog;\n this.#configCatalogSnapshot = config.catalogSnapshot;\n this.#configCatalogCell = config.catalogCell;\n this.#createAuth = runtime.createAuth;\n }\n\n get realtime(): PolyesterRealtime {\n if (!this.#realtime) {\n if (this.#configRealtimeClient) {\n this.#realtime = this.#configRealtimeClient;\n } else {\n const environment = this.#environment;\n const realtimeAuth = realtimeAuthFromProvider(this.#authProvider);\n this.#realtime = new RealtimeClient({\n wsUrl: environment.websocketUrl,\n tokenEndpoint: `${environment.apiUrl}/v1/rt/token`,\n subscribeEndpoint: `${environment.apiUrl}/v1/rt/subscribe`,\n getAuthHeaders:\n this.#realtimeConfig?.getAuthHeaders ?? realtimeAuth.getAuthHeaders,\n hasAuth: this.#realtimeConfig?.hasAuth ?? realtimeAuth.hasAuth,\n });\n }\n }\n return this.#realtime;\n }\n\n get catalog(): ClientCatalog {\n if (!this.#catalog) {\n if (this.#configCatalog) {\n this.#catalog = this.#configCatalog;\n } else {\n const catalogRefreshMarketData = new MarketDataService(\n this.transports,\n this.realtime,\n this.#getScales(),\n );\n const catalogRefreshZipper = new ZipperService(this.transports);\n this.#catalog = createPolyesterCatalog({\n snapshot: this.#configCatalogSnapshot,\n cell: this.#configCatalogCell,\n refresh: {\n market: () => catalogRefreshMarketData.getSpotConfig(),\n zipper: () => catalogRefreshZipper.getDepositWithdrawConfig(),\n },\n });\n }\n }\n return this.#catalog;\n }\n\n #getScales(): SdkScales {\n // Lazy catalog binding: the resolver only dereferences `this.catalog` at\n // call time. getSpotConfig() (the catalog's own refresh source) never\n // awaits scale readiness.\n this.#scales ??= createCatalogSdkScales(() => this.catalog);\n return this.#scales;\n }\n\n #getResolver(): SubaccountResolver | undefined {\n if (!this.#resolverInitialized) {\n this.#resolverInitialized = true;\n this.#resolver = this.createSubaccountResolver();\n }\n return this.#resolver;\n }\n\n get auth(): AuthService {\n if (!this.#auth) {\n this.#auth =\n this.#createAuth?.({\n transports: this.transports,\n realtime: this.realtime,\n subaccounts: this.subaccounts,\n environment: this.#environment,\n }) ?? new AuthService(this.transports, this.realtime);\n }\n return this.#auth;\n }\n\n get accounts(): AccountsService {\n return (this.#accounts ??= new AccountsService(this.transports));\n }\n\n get apiKeys(): ApiKeysService {\n return (this.#apiKeys ??= new ApiKeysService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get subaccounts(): SubaccountsService {\n return (this.#subaccounts ??= new SubaccountsService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get candles(): CandlesService {\n return (this.#candles ??= new CandlesService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get chainAnalytics(): ChainAnalyticsService {\n return (this.#chainAnalytics ??= new ChainAnalyticsService(\n this.transports,\n this.#getScales(),\n ));\n }\n\n get marketData(): MarketDataService {\n return (this.#marketData ??= new MarketDataService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get marketOverview(): MarketOverviewService {\n return (this.#marketOverview ??= new MarketOverviewService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get orderbook(): OrderbookService {\n return (this.#orderbook ??= new OrderbookService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get heatmap(): HeatmapService {\n return (this.#heatmap ??= new HeatmapService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get lifecycle(): LifecycleService {\n return (this.#lifecycle ??= new LifecycleService(this.transports, this.realtime));\n }\n\n get trades(): TradesService {\n return (this.#trades ??= new TradesService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get orders(): OrdersService {\n return (this.#orders ??= new OrdersService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get triggers(): TriggersService {\n return (this.#triggers ??= new TriggersService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get balances(): BalancesService {\n return (this.#balances ??= new BalancesService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get transfers(): TransfersService {\n return (this.#transfers ??= new TransfersService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get internalTransfers(): InternalTransfersService {\n return (this.#internalTransfers ??= new InternalTransfersService(\n this.transports,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get tradingWithdraws(): TradingWithdrawsService {\n return (this.#tradingWithdraws ??= new TradingWithdrawsService(\n this.transports,\n this.#getResolver(),\n {\n chainId: this.#environment.chain.id,\n tradingGatewayAddress: this.#environment.contracts.tradingGatewayAddress,\n },\n this.#getScales(),\n this.catalog,\n ));\n }\n\n get deposit(): DepositService {\n return (this.#deposit ??= new DepositService(this.transports, this.#getResolver()));\n }\n\n get addressBook(): AddressBookService {\n return (this.#addressBook ??= new AddressBookService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get guardSigner(): GuardSignerService {\n return (this.#guardSigner ??= new GuardSignerService(this.transports, this.#getResolver()));\n }\n\n get socialVerification(): SocialVerificationService {\n return (this.#socialVerification ??= new SocialVerificationService(this.transports));\n }\n\n get whiteboard(): WhiteboardService {\n return (this.#whiteboard ??= new WhiteboardService(this.transports));\n }\n\n get zipper(): ZipperService {\n return (this.#zipper ??= new ZipperService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get mfa(): MfaService {\n return (this.#mfa ??= new MfaService(this.transports));\n }\n\n get vip(): VipService {\n return (this.#vip ??= new VipService(this.transports));\n }\n\n get fees(): FeesService {\n return (this.#fees ??= new FeesService(this.transports, this.#getResolver()));\n }\n\n get tradingRateLimits(): RateLimitService {\n return (this.#tradingRateLimits ??= new RateLimitService(\n this.transports,\n this.#getResolver(),\n ));\n }\n\n /**\n * Override in subclasses to provide a subaccount resolver.\n * The resolver is called lazily when service methods are invoked.\n */\n protected createSubaccountResolver(): SubaccountResolver | undefined {\n return undefined;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"core-client.js","names":["#environment","#authProvider","#realtimeConfig","#configRealtimeClient","#configCatalog","#configCatalogSnapshot","#configCatalogCell","#createAuth","#realtime","#catalog","#getScales","#scales","#resolverInitialized","#resolver","#auth","#accounts","#apiKeys","#getResolver","#subaccounts","#candles","#chainAnalytics","#marketData","#marketOverview","#orderbook","#heatmap","#lifecycle","#trades","#orders","#triggers","#balances","#transfers","#internalTransfers","#tradingWithdraws","#deposit","#addressBook","#guardSigner","#socialVerification","#whiteboard","#zipper","#mfa","#vip","#fees","#tradingRateLimits"],"sources":["../src/core-client.ts"],"sourcesContent":["import type { Interceptor } from \"@connectrpc/connect\";\nimport { ConfigurationError } from \"./shared/errors.js\";\nimport {\n createApiKeyEd25519AuthHeaders,\n createTransports,\n resolveJwtToken,\n type AuthAndPublicApiTransports,\n type Transports,\n type JwtAuthProvider,\n type ApiKeyEd25519AuthProvider,\n} from \"./shared/transports.js\";\nimport { parsePolyesterEnvironment, type PolyesterEnvironment } from \"./environment.js\";\nimport { AccountsService } from \"./services/accounts/index.js\";\nimport { ApiKeysService } from \"./services/api-keys/index.js\";\nimport { AuthService } from \"./services/auth/auth.js\";\nimport { SubaccountsService } from \"./services/subaccounts/index.js\";\nimport { CandlesService } from \"./services/candles/index.js\";\nimport { ChainAnalyticsService } from \"./services/chain-analytics/index.js\";\nimport { MarketDataService } from \"./services/market-data/index.js\";\nimport { MarketOverviewService } from \"./services/market-overview/index.js\";\nimport { OrderbookService } from \"./services/orderbook/index.js\";\nimport { HeatmapService } from \"./services/heatmap/index.js\";\nimport { LifecycleService } from \"./services/lifecycle/index.js\";\nimport { TradesService } from \"./services/trades/index.js\";\nimport { OrdersService } from \"./services/orders/index.js\";\nimport { TriggersService } from \"./services/triggers/index.js\";\nimport { BalancesService } from \"./services/balances/index.js\";\nimport { TransfersService } from \"./services/transfers/index.js\";\nimport { InternalTransfersService } from \"./services/internal-transfers/index.js\";\nimport { TradingWithdrawsService } from \"./services/trading-withdraws/index.js\";\nimport { DepositService } from \"./services/deposit/index.js\";\nimport { AddressBookService } from \"./services/address-book/index.js\";\nimport { GuardSignerService } from \"./services/guard-signer/index.js\";\nimport { SocialVerificationService } from \"./services/social-verification/index.js\";\nimport { WhiteboardService } from \"./services/whiteboard/index.js\";\nimport { ZipperService } from \"./services/zipper/index.js\";\nimport { MfaService } from \"./services/mfa/index.js\";\nimport { VipService } from \"./services/vip/index.js\";\nimport { FeesService } from \"./services/fees/index.js\";\nimport { RateLimitService } from \"./services/rate-limits/index.js\";\nimport type { SubaccountResolver } from \"./services/subaccount-resolver.js\";\nimport {\n createPolyesterCatalog,\n type CatalogSnapshot,\n type CatalogSnapshotCell,\n type ClientCatalog,\n} from \"./catalogs/index.js\";\nimport { createCatalogSdkScales, type SdkScales } from \"./shared/decimal-surface.js\";\nimport { RealtimeClient, type PolyesterRealtime, type RealtimeConfig } from \"./realtime/index.js\";\n\nfunction realtimeAuthFromProvider(\n auth: JwtAuthProvider | ApiKeyEd25519AuthProvider | undefined,\n): Pick<RealtimeConfig, \"getAuthHeaders\" | \"hasAuth\"> {\n if (!auth) return {};\n if (auth.kind === \"jwt\") {\n return {\n getAuthHeaders: async () => {\n const token = await resolveJwtToken(auth);\n const headers: Record<string, string> = {};\n if (token) headers.authorization = `Bearer ${token}`;\n return headers;\n },\n hasAuth: () => {\n try {\n const token = auth.getToken();\n if (token !== null && typeof token !== \"string\") {\n // Async credentials are validated by the token request.\n void token.catch(() => {});\n return true;\n }\n return token !== null && token.length > 0;\n } catch {\n // Let the token request report provider failures as AuthenticationError.\n return true;\n }\n },\n };\n }\n return {\n getAuthHeaders: (request) =>\n createApiKeyEd25519AuthHeaders(auth, {\n url: request.url,\n method: request.method,\n }),\n hasAuth: () => true,\n };\n}\n\nexport type PolyesterRealtimeAuthConfig = Pick<RealtimeConfig, \"getAuthHeaders\" | \"hasAuth\">;\n\ninterface PolyesterClientCommonConfig {\n environment: PolyesterEnvironment;\n interceptors?: Interceptor[];\n auth?: JwtAuthProvider | ApiKeyEd25519AuthProvider;\n realtime?: PolyesterRealtimeAuthConfig;\n /**\n * Connect wire format. Defaults to binary for production performance.\n * Use `json` for human-readable debugging.\n */\n wireFormat?: \"binary\" | \"json\";\n /**\n * Advanced: inject pre-built Connect transports (in-memory mocks, custom\n * stacks). When provided, the SDK does not build its own transports and the\n * built-in auth/error-mapping interceptors are NOT applied — the injected\n * transports own their full interceptor chain.\n */\n transports?: Transports;\n /**\n * Advanced: inject a realtime implementation (in-memory mocks, custom\n * stacks). When provided, the SDK skips constructing its Centrifuge-backed\n * realtime client and the `realtime` auth config is ignored.\n */\n realtimeClient?: PolyesterRealtime;\n}\n\ntype PolyesterCatalogConfig =\n | {\n /** Client-owned catalog store. */\n catalog: ClientCatalog;\n catalogSnapshot?: never;\n catalogCell?: never;\n }\n | {\n catalog?: never;\n /**\n * Explicit initial catalog snapshot, commonly hydrated from server-rendered data.\n * Combines with `catalogCell` as the cell's initial value without clobbering a\n * pre-populated cell.\n */\n catalogSnapshot?: CatalogSnapshot;\n /**\n * External snapshot storage for the client-built catalog. A cell backed by a\n * reactive source makes every catalog read reactive.\n */\n catalogCell?: CatalogSnapshotCell;\n };\n\n/** Configuration shared by every Polyester client. */\nexport type PolyesterClientBaseConfig = PolyesterClientCommonConfig & PolyesterCatalogConfig;\n\n/** Configuration for the base Polyester client. */\nexport type PolyesterClientConfig = PolyesterClientBaseConfig;\n\n/** Preserves the exclusive catalog configuration while projecting client config fields. */\nexport function pickPolyesterCatalogConfig(\n config: PolyesterClientBaseConfig,\n): PolyesterCatalogConfig {\n return config.catalog === undefined\n ? {\n catalogSnapshot: config.catalogSnapshot,\n catalogCell: config.catalogCell,\n }\n : { catalog: config.catalog };\n}\n\ninterface AuthServiceFactoryContext {\n transports: AuthAndPublicApiTransports;\n realtime: PolyesterRealtime;\n subaccounts: SubaccountsService;\n environment: PolyesterEnvironment;\n}\n\ninterface PolyesterClientRuntimeConfig {\n createAuth?: (context: AuthServiceFactoryContext) => AuthService;\n}\n\n/**\n * Parses the configuration shared by every public client constructor.\n */\nexport function parsePolyesterClientConfig<TConfig extends PolyesterClientBaseConfig>(\n config: TConfig,\n): TConfig {\n if (typeof config !== \"object\" || config === null || Array.isArray(config)) {\n throw new ConfigurationError(\"Client configuration must be an object.\");\n }\n const environment = parsePolyesterEnvironment(config.environment);\n if (\n config.wireFormat !== undefined &&\n config.wireFormat !== \"binary\" &&\n config.wireFormat !== \"json\"\n ) {\n throw new ConfigurationError('wireFormat must be either \"binary\" or \"json\".');\n }\n if (config.catalog && config.catalogSnapshot) {\n throw new ConfigurationError(\"Provide either catalog or catalogSnapshot, not both.\");\n }\n if (config.catalog && config.catalogCell) {\n throw new ConfigurationError(\"Provide either catalog or catalogCell, not both.\");\n }\n\n return Object.assign({}, config, { environment });\n}\n\n/**\n * Base SDK client that wires transports, realtime, catalogs, and all public service clients for a Polyester environment.\n *\n * Services are constructed lazily on first property access (and memoized) so\n * that creating a client — which happens for every SSR request in server\n * hooks — only pays for the services the caller actually touches.\n */\nexport class PolyesterClient {\n protected readonly transports: Transports;\n\n readonly #environment: PolyesterEnvironment;\n readonly #authProvider: JwtAuthProvider | ApiKeyEd25519AuthProvider | undefined;\n readonly #realtimeConfig: PolyesterRealtimeAuthConfig | undefined;\n readonly #configRealtimeClient: PolyesterRealtime | undefined;\n readonly #configCatalog: ClientCatalog | undefined;\n readonly #configCatalogSnapshot: CatalogSnapshot | undefined;\n readonly #configCatalogCell: CatalogSnapshotCell | undefined;\n readonly #createAuth: PolyesterClientRuntimeConfig[\"createAuth\"];\n\n #realtime: PolyesterRealtime | undefined;\n #catalog: ClientCatalog | undefined;\n #scales: SdkScales | undefined;\n #resolver: SubaccountResolver | undefined;\n #resolverInitialized = false;\n\n #auth: AuthService | undefined;\n #accounts: AccountsService | undefined;\n #apiKeys: ApiKeysService | undefined;\n #subaccounts: SubaccountsService | undefined;\n #candles: CandlesService | undefined;\n #chainAnalytics: ChainAnalyticsService | undefined;\n #marketData: MarketDataService | undefined;\n #marketOverview: MarketOverviewService | undefined;\n #orderbook: OrderbookService | undefined;\n #heatmap: HeatmapService | undefined;\n #lifecycle: LifecycleService | undefined;\n #trades: TradesService | undefined;\n #orders: OrdersService | undefined;\n #triggers: TriggersService | undefined;\n #balances: BalancesService | undefined;\n #transfers: TransfersService | undefined;\n #internalTransfers: InternalTransfersService | undefined;\n #tradingWithdraws: TradingWithdrawsService | undefined;\n #deposit: DepositService | undefined;\n #addressBook: AddressBookService | undefined;\n #guardSigner: GuardSignerService | undefined;\n #socialVerification: SocialVerificationService | undefined;\n #whiteboard: WhiteboardService | undefined;\n #zipper: ZipperService | undefined;\n #mfa: MfaService | undefined;\n #vip: VipService | undefined;\n #fees: FeesService | undefined;\n #tradingRateLimits: RateLimitService | undefined;\n\n constructor(config: PolyesterClientConfig, runtime: PolyesterClientRuntimeConfig = {}) {\n const parsedConfig = parsePolyesterClientConfig(config);\n config = parsedConfig;\n const interceptors = config.interceptors ?? [];\n const { environment } = config;\n\n this.transports =\n config.transports ??\n createTransports({\n apiUrl: environment.apiUrl,\n interceptors,\n auth: config.auth,\n wireFormat: config.wireFormat,\n });\n\n this.#environment = environment;\n this.#authProvider = config.auth;\n this.#realtimeConfig = config.realtime;\n this.#configRealtimeClient = config.realtimeClient;\n this.#configCatalog = config.catalog;\n this.#configCatalogSnapshot = config.catalogSnapshot;\n this.#configCatalogCell = config.catalogCell;\n this.#createAuth = runtime.createAuth;\n }\n\n get realtime(): PolyesterRealtime {\n if (!this.#realtime) {\n if (this.#configRealtimeClient) {\n this.#realtime = this.#configRealtimeClient;\n } else {\n const environment = this.#environment;\n const realtimeAuth = realtimeAuthFromProvider(this.#authProvider);\n this.#realtime = new RealtimeClient({\n wsUrl: environment.websocketUrl,\n tokenEndpoint: `${environment.apiUrl}/v1/rt/token`,\n subscribeEndpoint: `${environment.apiUrl}/v1/rt/subscribe`,\n getAuthHeaders:\n this.#realtimeConfig?.getAuthHeaders ?? realtimeAuth.getAuthHeaders,\n hasAuth: this.#realtimeConfig?.hasAuth ?? realtimeAuth.hasAuth,\n });\n }\n }\n return this.#realtime;\n }\n\n get catalog(): ClientCatalog {\n if (!this.#catalog) {\n if (this.#configCatalog) {\n this.#catalog = this.#configCatalog;\n } else {\n const catalogRefreshMarketData = new MarketDataService(\n this.transports,\n this.realtime,\n this.#getScales(),\n );\n const catalogRefreshZipper = new ZipperService(this.transports);\n this.#catalog = createPolyesterCatalog({\n snapshot: this.#configCatalogSnapshot,\n cell: this.#configCatalogCell,\n refresh: {\n market: () => catalogRefreshMarketData.getSpotConfig(),\n zipper: () => catalogRefreshZipper.getDepositWithdrawConfig(),\n },\n });\n }\n }\n return this.#catalog;\n }\n\n #getScales(): SdkScales {\n // Lazy catalog binding: the resolver only dereferences `this.catalog` at\n // call time. getSpotConfig() (the catalog's own refresh source) never\n // awaits scale readiness.\n this.#scales ??= createCatalogSdkScales(() => this.catalog);\n return this.#scales;\n }\n\n #getResolver(): SubaccountResolver | undefined {\n if (!this.#resolverInitialized) {\n this.#resolverInitialized = true;\n this.#resolver = this.createSubaccountResolver();\n }\n return this.#resolver;\n }\n\n get auth(): AuthService {\n if (!this.#auth) {\n this.#auth =\n this.#createAuth?.({\n transports: this.transports,\n realtime: this.realtime,\n subaccounts: this.subaccounts,\n environment: this.#environment,\n }) ?? new AuthService(this.transports, this.realtime);\n }\n return this.#auth;\n }\n\n get accounts(): AccountsService {\n return (this.#accounts ??= new AccountsService(this.transports));\n }\n\n get apiKeys(): ApiKeysService {\n return (this.#apiKeys ??= new ApiKeysService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get subaccounts(): SubaccountsService {\n return (this.#subaccounts ??= new SubaccountsService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get candles(): CandlesService {\n return (this.#candles ??= new CandlesService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get chainAnalytics(): ChainAnalyticsService {\n return (this.#chainAnalytics ??= new ChainAnalyticsService(\n this.transports,\n this.#getScales(),\n ));\n }\n\n get marketData(): MarketDataService {\n return (this.#marketData ??= new MarketDataService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get marketOverview(): MarketOverviewService {\n return (this.#marketOverview ??= new MarketOverviewService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get orderbook(): OrderbookService {\n return (this.#orderbook ??= new OrderbookService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get heatmap(): HeatmapService {\n return (this.#heatmap ??= new HeatmapService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get lifecycle(): LifecycleService {\n return (this.#lifecycle ??= new LifecycleService(this.transports, this.realtime));\n }\n\n get trades(): TradesService {\n return (this.#trades ??= new TradesService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get orders(): OrdersService {\n return (this.#orders ??= new OrdersService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get triggers(): TriggersService {\n return (this.#triggers ??= new TriggersService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get balances(): BalancesService {\n return (this.#balances ??= new BalancesService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get transfers(): TransfersService {\n return (this.#transfers ??= new TransfersService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get internalTransfers(): InternalTransfersService {\n return (this.#internalTransfers ??= new InternalTransfersService(\n this.transports,\n this.#getResolver(),\n this.#getScales(),\n ));\n }\n\n get tradingWithdraws(): TradingWithdrawsService {\n return (this.#tradingWithdraws ??= new TradingWithdrawsService(\n this.transports,\n this.#getResolver(),\n {\n chainId: this.#environment.chain.id,\n tradingGatewayAddress: this.#environment.contracts.tradingGatewayAddress,\n },\n this.#getScales(),\n this.catalog,\n ));\n }\n\n get deposit(): DepositService {\n return (this.#deposit ??= new DepositService(this.transports, this.#getResolver()));\n }\n\n get addressBook(): AddressBookService {\n return (this.#addressBook ??= new AddressBookService(\n this.transports,\n this.realtime,\n this.#getResolver(),\n ));\n }\n\n get guardSigner(): GuardSignerService {\n return (this.#guardSigner ??= new GuardSignerService(this.transports, this.#getResolver()));\n }\n\n get socialVerification(): SocialVerificationService {\n return (this.#socialVerification ??= new SocialVerificationService(this.transports));\n }\n\n get whiteboard(): WhiteboardService {\n return (this.#whiteboard ??= new WhiteboardService(this.transports));\n }\n\n get zipper(): ZipperService {\n return (this.#zipper ??= new ZipperService(\n this.transports,\n this.realtime,\n this.#getScales(),\n ));\n }\n\n get mfa(): MfaService {\n return (this.#mfa ??= new MfaService(this.transports));\n }\n\n get vip(): VipService {\n return (this.#vip ??= new VipService(this.transports));\n }\n\n get fees(): FeesService {\n return (this.#fees ??= new FeesService(this.transports, this.#getResolver()));\n }\n\n get tradingRateLimits(): RateLimitService {\n return (this.#tradingRateLimits ??= new RateLimitService(\n this.transports,\n this.#getResolver(),\n ));\n }\n\n /**\n * Override in subclasses to provide a subaccount resolver.\n * The resolver is called lazily when service methods are invoked.\n */\n protected createSubaccountResolver(): SubaccountResolver | undefined {\n return undefined;\n }\n}\n"],"mappings":"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"}
@@ -29,7 +29,6 @@ function loadCentrifuge() {
29
29
  var RealtimeClient = class {
30
30
  #publicClient = null;
31
31
  #privateClient = null;
32
- #connectionHandlers = /* @__PURE__ */ new Set();
33
32
  #sharedSubs = /* @__PURE__ */ new Map();
34
33
  #pendingTeardowns = /* @__PURE__ */ new Map();
35
34
  #config;
@@ -83,13 +82,10 @@ var RealtimeClient = class {
83
82
  #createPublicClient(Centrifuge) {
84
83
  const client = new Centrifuge(this.#config.wsUrl);
85
84
  this.#publicClient = client;
86
- client.on("connected", () => {
87
- if (this.#publicClient !== client) return;
88
- for (const h of this.#connectionHandlers) h.onConnected?.();
89
- });
90
- client.on("disconnected", () => {
91
- if (this.#publicClient !== client) return;
92
- for (const h of this.#connectionHandlers) h.onDisconnected?.();
85
+ client.on("disconnected", (ctx) => {
86
+ if (this.#publicClient !== client || ctx.code <= 1) return;
87
+ this.#publicClient = null;
88
+ this.#terminateSubscriptions([...this.#sharedSubs.values(), ...this.#pendingTeardowns.values()].filter((shared) => shared.client === client), "disconnected", ctx);
93
89
  });
94
90
  client.connect();
95
91
  return client;
@@ -114,13 +110,10 @@ var RealtimeClient = class {
114
110
  }
115
111
  } });
116
112
  this.#privateClient = client;
117
- client.on("connected", () => {
118
- if (this.#privateClient !== client) return;
119
- for (const h of this.#connectionHandlers) h.onConnected?.();
120
- });
121
- client.on("disconnected", () => {
122
- if (this.#privateClient !== client) return;
123
- for (const h of this.#connectionHandlers) h.onDisconnected?.();
113
+ client.on("disconnected", (ctx) => {
114
+ if (this.#privateClient !== client || ctx.code <= 1) return;
115
+ this.#privateClient = null;
116
+ this.#terminateSubscriptions([...this.#sharedSubs.values(), ...this.#pendingTeardowns.values()].filter((shared) => shared.client === client), "disconnected", ctx);
124
117
  });
125
118
  client.connect();
126
119
  return client;
@@ -128,16 +121,11 @@ var RealtimeClient = class {
128
121
  #ensurePublicClient(Centrifuge) {
129
122
  return this.#publicClient ?? this.#createPublicClient(Centrifuge);
130
123
  }
131
- #ensurePrivateClient(Centrifuge) {
132
- if (!this.#hasAuth()) throw new AuthenticationError("Cannot create authenticated realtime client without authentication");
133
- return this.#privateClient ?? this.#createPrivateClient(Centrifuge);
134
- }
135
124
  #assertChannelAuth(channel) {
136
125
  if (this.#channelKind(channel) === "private" && !this.#hasAuth()) throw new AuthenticationError(`Cannot subscribe to private channel "${channel}" without authentication`);
137
126
  }
138
127
  #ensureClientForChannel(Centrifuge, channel) {
139
- this.#assertChannelAuth(channel);
140
- if (this.#channelKind(channel) === "private") return this.#ensurePrivateClient(Centrifuge);
128
+ if (this.#channelKind(channel) === "private") return this.#privateClient ?? this.#createPrivateClient(Centrifuge);
141
129
  return this.#ensurePublicClient(Centrifuge);
142
130
  }
143
131
  #attachSubscription(shared) {
@@ -164,6 +152,7 @@ var RealtimeClient = class {
164
152
  if (shared.attachmentEpoch !== attachmentEpoch || shared.sub) return;
165
153
  if (this.#sharedSubs.get(shared.channel) !== shared) return;
166
154
  try {
155
+ this.#assertChannelAuth(shared.channel);
167
156
  this.#attachSubscriptionNow(Centrifuge, shared, attachmentEpoch);
168
157
  } catch (error) {
169
158
  this.#sharedSubs.delete(shared.channel);
@@ -184,8 +173,12 @@ var RealtimeClient = class {
184
173
  const subscriptionEpoch = ++shared.subscriptionEpoch;
185
174
  for (const handler of shared.subscribedHandlers) handler(subscriptionEpoch);
186
175
  });
187
- sub.on("unsubscribed", () => {
176
+ sub.on("unsubscribed", (ctx) => {
188
177
  if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;
178
+ if (ctx.code >= 2e3 && ctx.code < 2500) {
179
+ this.#terminateSubscriptions([shared], "unsubscribed", ctx);
180
+ return;
181
+ }
189
182
  for (const handler of shared.unsubscribedHandlers) handler();
190
183
  });
191
184
  sub.on("error", (ctx) => {
@@ -240,6 +233,29 @@ var RealtimeClient = class {
240
233
  this.#callErrorHandler(onError, createSdkSubscriptionErrorContext(channel, type, error));
241
234
  }
242
235
  }
236
+ #terminateSubscriptions(subscriptions, type, ctx) {
237
+ const notifications = subscriptions.map((shared) => ({
238
+ error: createSdkSubscriptionErrorContext(shared.channel, type, {
239
+ code: ctx.code,
240
+ message: ctx.reason
241
+ }),
242
+ errorHandlers: [...shared.errorHandlers],
243
+ closeHandlers: [...shared.unsubscribedHandlers]
244
+ }));
245
+ for (const shared of subscriptions) {
246
+ if (this.#sharedSubs.get(shared.channel) === shared) this.#sharedSubs.delete(shared.channel);
247
+ if (this.#pendingTeardowns.get(shared.channel) === shared) this.#pendingTeardowns.delete(shared.channel);
248
+ this.#teardownSubscription(shared);
249
+ shared.publicationHandlers.clear();
250
+ shared.subscribedHandlers.clear();
251
+ shared.unsubscribedHandlers.clear();
252
+ shared.errorHandlers.clear();
253
+ }
254
+ for (const { error, errorHandlers, closeHandlers } of notifications) {
255
+ for (const handler of errorHandlers) handler(error);
256
+ for (const handler of closeHandlers) handler();
257
+ }
258
+ }
243
259
  #teardownSubscription(shared) {
244
260
  const sub = shared.sub;
245
261
  const client = shared.client;
@@ -283,7 +299,6 @@ var RealtimeClient = class {
283
299
  try {
284
300
  privateClient?.disconnect();
285
301
  } catch {}
286
- this.#connectionHandlers.clear();
287
302
  }
288
303
  #disconnectPrivate() {
289
304
  const privateClient = this.#privateClient;
@@ -339,9 +354,13 @@ var RealtimeClient = class {
339
354
  if (onSubscribed) shared.subscribedHandlers.add(onSubscribed);
340
355
  if (onUnsubscribed) shared.unsubscribedHandlers.add(onUnsubscribed);
341
356
  if (onError) shared.errorHandlers.add(onError);
342
- if (this.#channelKind(channel) === "private" && this.#hasAuth()) {
343
- if (shared.client?.state === "disconnected") shared.client.connect();
344
- if (shared.sub?.state === "unsubscribed") shared.sub.subscribe();
357
+ if (this.#channelKind(channel) === "private") {
358
+ const reconnect = shared.client?.state === "disconnected";
359
+ const resubscribe = shared.sub?.state === "unsubscribed";
360
+ if ((reconnect || resubscribe) && this.#hasAuth()) {
361
+ if (reconnect) shared.client?.connect();
362
+ if (resubscribe) shared.sub?.subscribe();
363
+ }
345
364
  }
346
365
  let closed = false;
347
366
  if (onSubscribed && shared.sub?.state === "subscribed") {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["#config","#getAuthHeaders","#sharedSubs","#channelKind","#emitSubscriptionError","#publicClient","#connectionHandlers","#privateClient","#emitConnectionTokenError","#createPublicClient","#hasAuth","#createPrivateClient","#assertChannelAuth","#ensurePrivateClient","#ensurePublicClient","#attachSubscriptionNow","#attachSubscriptionWhenLoaded","#ensureClientForChannel","#subscriptionOpts","#pendingTeardowns","#attachSubscription","#callErrorHandler","#disconnectClientIfIdle","#hasChannelsForKind","#teardownSubscription","#getOrCreateSubscription","#callConsumerHandler","#disconnect","#disconnectPrivate"],"sources":["../../src/realtime/client.ts"],"sourcesContent":["import { fromBinary, type DescMessage, type MessageShape } from \"@bufbuild/protobuf\";\nimport type {\n Centrifuge,\n SubscriptionErrorContext,\n PublicationContext,\n Subscription,\n} from \"centrifuge/build/protobuf\";\nimport type * as CentrifugeModule from \"centrifuge/build/protobuf\";\nimport {\n createSdkSubscriptionErrorContext,\n fromCentrifugeSubscriptionError,\n type SdkSubscriptionErrorContext,\n} from \"../shared/subscription-errors.js\";\nimport {\n AuthenticationError,\n errorFromHttpStatus,\n InternalServerError,\n PolyesterError,\n} from \"../shared/errors.js\";\nimport { makeFetch } from \"../shared/transports.js\";\nimport { decodeProtoFrame } from \"../utils/streams.js\";\nimport type { ConnectChannelParams, PolyesterRealtime, SubscribeHandlers } from \"./types.js\";\n\nconst realtimeFetch = makeFetch();\n\ntype CentrifugeCtor = typeof CentrifugeModule.Centrifuge;\ntype CentrifugeModuleLoader = () => Promise<typeof CentrifugeModule>;\n\nconst defaultCentrifugeModuleLoader: CentrifugeModuleLoader = () =>\n import(\"centrifuge/build/protobuf\");\n\n// Centrifuge's protobuf build embeds the protobuf.js runtime (~300 KB minified).\n// Loading it lazily keeps it out of the eager module graph on both the server\n// (Cloudflare isolate cold start — SSR never opens a websocket) and the client\n// app shell; it is only fetched when the first subscription attaches.\nlet centrifugeCtorPromise: Promise<CentrifugeCtor> | null = null;\nlet loadedCentrifugeCtor: CentrifugeCtor | null = null;\nlet centrifugeModuleLoader = defaultCentrifugeModuleLoader;\nexport function __setRealtimeCentrifugeForTests(Centrifuge: CentrifugeCtor | null): void {\n loadedCentrifugeCtor = Centrifuge;\n centrifugeCtorPromise = Centrifuge ? Promise.resolve(Centrifuge) : null;\n}\n\n/** Replaces the lazy Centrifuge module loader for isolated transport-load tests. */\nexport function __setRealtimeCentrifugeLoaderForTests(loader: CentrifugeModuleLoader | null): void {\n centrifugeModuleLoader = loader ?? defaultCentrifugeModuleLoader;\n loadedCentrifugeCtor = null;\n centrifugeCtorPromise = null;\n}\n\nfunction loadCentrifuge(): Promise<CentrifugeCtor> {\n if (\n centrifugeModuleLoader === defaultCentrifugeModuleLoader &&\n (import.meta as { env?: { SSR?: boolean } }).env?.SSR\n ) {\n return Promise.reject(new Error(\"Realtime subscriptions are browser-only during SSR.\"));\n }\n\n if (!centrifugeCtorPromise) {\n const loadAttempt = Promise.resolve().then(centrifugeModuleLoader);\n const retryableLoad = loadAttempt.then(\n (mod) => {\n loadedCentrifugeCtor = mod.Centrifuge;\n return mod.Centrifuge;\n },\n (error) => {\n if (centrifugeCtorPromise === retryableLoad) centrifugeCtorPromise = null;\n throw error;\n },\n );\n centrifugeCtorPromise = retryableLoad;\n }\n return centrifugeCtorPromise;\n}\n\nexport interface RealtimeAuthRequest {\n url: string | URL;\n method: string;\n}\n\nexport interface RealtimeConfig {\n wsUrl: string;\n tokenEndpoint: string;\n subscribeEndpoint: string;\n getAuthHeaders?: (request: RealtimeAuthRequest) => Promise<HeadersInit> | HeadersInit;\n hasAuth?: () => boolean;\n}\n\ntype ResolvedRealtimeConfig = Pick<\n RealtimeConfig,\n \"wsUrl\" | \"tokenEndpoint\" | \"subscribeEndpoint\"\n> & {\n getAuthHeaders: (request: RealtimeAuthRequest) => Promise<HeadersInit> | HeadersInit;\n hasAuth: () => boolean;\n};\n\nexport type { ConnectChannelParams, PolyesterRealtime, SubscribeHandlers } from \"./types.js\";\n\ntype ConnectionHandler = { onConnected?: () => void; onDisconnected?: () => void };\ntype PublicationHandler<T = unknown> = (data: T) => void;\ntype ErrorHandler = (ctx: SdkSubscriptionErrorContext) => void;\ntype RealtimeClientKind = \"public\" | \"private\";\n\ninterface SharedSubscription {\n channel: string;\n sub: Subscription | null;\n client: Centrifuge | null;\n attachmentEpoch: number;\n consumers: number;\n subscriptionEpoch: number;\n publicationHandlers: Set<PublicationHandler>;\n subscribedHandlers: Set<(epoch: number) => void>;\n unsubscribedHandlers: Set<() => void>;\n errorHandlers: Set<ErrorHandler>;\n}\n\n/**\n * Shared Centrifuge realtime client that multiplexes public and private protobuf subscriptions across SDK services.\n */\nexport class RealtimeClient implements PolyesterRealtime {\n #publicClient: Centrifuge | null = null;\n #privateClient: Centrifuge | null = null;\n #connectionHandlers = new Set<ConnectionHandler>();\n #sharedSubs = new Map<string, SharedSubscription>();\n #pendingTeardowns = new Map<string, SharedSubscription>();\n readonly #config: ResolvedRealtimeConfig;\n\n constructor(config: RealtimeConfig) {\n this.#config = {\n wsUrl: config.wsUrl,\n tokenEndpoint: config.tokenEndpoint,\n subscribeEndpoint: config.subscribeEndpoint,\n getAuthHeaders: config.getAuthHeaders ?? (() => ({})),\n hasAuth: config.hasAuth ?? (() => false),\n };\n }\n\n async #getAuthHeaders(request: RealtimeAuthRequest): Promise<HeadersInit> {\n return this.#config.getAuthHeaders(request);\n }\n\n #emitSubscriptionError(shared: SharedSubscription, type: string, error: unknown): void {\n const ctx = createSdkSubscriptionErrorContext(shared.channel, type, error);\n for (const handler of shared.errorHandlers) {\n handler(ctx);\n }\n }\n\n #emitConnectionTokenError(error: unknown): void {\n for (const shared of this.#sharedSubs.values()) {\n if (this.#channelKind(shared.channel) === \"private\") {\n this.#emitSubscriptionError(shared, \"connection_token\", error);\n }\n }\n }\n\n #subscriptionOpts(\n Centrifuge: CentrifugeCtor,\n shared: SharedSubscription,\n attachmentEpoch: number,\n ) {\n if (this.#channelKind(shared.channel) !== \"private\") return undefined;\n return {\n getToken: async () => {\n try {\n const url = new URL(this.#config.subscribeEndpoint);\n url.searchParams.set(\"channel\", shared.channel);\n const headers = await this.#getAuthHeaders({ url, method: \"GET\" });\n const res = await realtimeFetch(url, { headers });\n if (!res.ok) {\n throw errorFromHttpStatus(\n res.status,\n `Failed to fetch subscription token: ${res.status}`,\n );\n }\n const json = (await res.json()) as { token?: string };\n if (!json?.token) {\n throw new InternalServerError(\"Subscription token response had no token\");\n }\n return json.token;\n } catch (error) {\n if (shared.attachmentEpoch === attachmentEpoch) {\n this.#emitSubscriptionError(shared, \"subscription_token\", error);\n }\n if (error instanceof PolyesterError && !error.retryable) {\n throw new Centrifuge.UnauthorizedError(error.message);\n }\n throw error;\n }\n },\n };\n }\n\n #hasAuth(): boolean {\n return this.#config.hasAuth();\n }\n\n #channelKind(channel: string): RealtimeClientKind {\n return channel.startsWith(\"private:\") ? \"private\" : \"public\";\n }\n\n #createPublicClient(Centrifuge: CentrifugeCtor): Centrifuge {\n const client = new Centrifuge(this.#config.wsUrl);\n this.#publicClient = client;\n\n client.on(\"connected\", () => {\n if (this.#publicClient !== client) return;\n for (const h of this.#connectionHandlers) h.onConnected?.();\n });\n client.on(\"disconnected\", () => {\n if (this.#publicClient !== client) return;\n for (const h of this.#connectionHandlers) h.onDisconnected?.();\n });\n\n client.connect();\n return client;\n }\n\n #createPrivateClient(Centrifuge: CentrifugeCtor): Centrifuge {\n let client: Centrifuge;\n const opts = {\n getToken: async () => {\n try {\n const headers = await this.#getAuthHeaders({\n url: this.#config.tokenEndpoint,\n method: \"GET\",\n });\n const res = await realtimeFetch(this.#config.tokenEndpoint, {\n headers,\n });\n if (!res.ok) {\n throw errorFromHttpStatus(\n res.status,\n `Failed to fetch connection token: ${res.status}`,\n );\n }\n const json = (await res.json()) as { token?: string };\n if (!json?.token) {\n throw new InternalServerError(\"Connection token response had no token\");\n }\n return json.token;\n } catch (error) {\n if (this.#privateClient === client) {\n this.#emitConnectionTokenError(error);\n }\n if (error instanceof PolyesterError && !error.retryable) {\n throw new Centrifuge.UnauthorizedError(error.message);\n }\n throw error;\n }\n },\n };\n\n client = new Centrifuge(this.#config.wsUrl, opts);\n this.#privateClient = client;\n\n client.on(\"connected\", () => {\n if (this.#privateClient !== client) return;\n for (const h of this.#connectionHandlers) h.onConnected?.();\n });\n client.on(\"disconnected\", () => {\n if (this.#privateClient !== client) return;\n for (const h of this.#connectionHandlers) h.onDisconnected?.();\n });\n\n client.connect();\n return client;\n }\n\n #ensurePublicClient(Centrifuge: CentrifugeCtor): Centrifuge {\n return this.#publicClient ?? this.#createPublicClient(Centrifuge);\n }\n\n #ensurePrivateClient(Centrifuge: CentrifugeCtor): Centrifuge {\n if (!this.#hasAuth()) {\n throw new AuthenticationError(\n \"Cannot create authenticated realtime client without authentication\",\n );\n }\n return this.#privateClient ?? this.#createPrivateClient(Centrifuge);\n }\n\n #assertChannelAuth(channel: string): void {\n if (this.#channelKind(channel) === \"private\" && !this.#hasAuth()) {\n throw new AuthenticationError(\n `Cannot subscribe to private channel \"${channel}\" without authentication`,\n );\n }\n }\n\n #ensureClientForChannel(Centrifuge: CentrifugeCtor, channel: string): Centrifuge {\n this.#assertChannelAuth(channel);\n if (this.#channelKind(channel) === \"private\") {\n return this.#ensurePrivateClient(Centrifuge);\n }\n\n return this.#ensurePublicClient(Centrifuge);\n }\n\n #attachSubscription(shared: SharedSubscription): void {\n if (shared.sub) return;\n\n // Auth failures must surface synchronously to subscribe() callers, as\n // they did when centrifuge was imported statically.\n this.#assertChannelAuth(shared.channel);\n\n const attachmentEpoch = shared.attachmentEpoch + 1;\n shared.attachmentEpoch = attachmentEpoch;\n\n // Once the transport module is loaded, attachment stays fully\n // synchronous — only the very first attach pays the dynamic import.\n if (loadedCentrifugeCtor) {\n this.#attachSubscriptionNow(loadedCentrifugeCtor, shared, attachmentEpoch);\n return;\n }\n void this.#attachSubscriptionWhenLoaded(shared, attachmentEpoch);\n }\n\n async #attachSubscriptionWhenLoaded(\n shared: SharedSubscription,\n attachmentEpoch: number,\n ): Promise<void> {\n let Centrifuge: CentrifugeCtor;\n try {\n Centrifuge = await loadCentrifuge();\n } catch (error) {\n if (shared.attachmentEpoch !== attachmentEpoch) return;\n if (this.#sharedSubs.get(shared.channel) === shared) {\n this.#sharedSubs.delete(shared.channel);\n }\n this.#emitSubscriptionError(shared, \"transport_load\", error);\n return;\n }\n\n // The subscription may have been torn down or re-attached while the\n // transport module was loading.\n if (shared.attachmentEpoch !== attachmentEpoch || shared.sub) return;\n if (this.#sharedSubs.get(shared.channel) !== shared) return;\n\n try {\n this.#attachSubscriptionNow(Centrifuge, shared, attachmentEpoch);\n } catch (error) {\n this.#sharedSubs.delete(shared.channel);\n this.#emitSubscriptionError(shared, \"auth\", error);\n }\n }\n\n #attachSubscriptionNow(\n Centrifuge: CentrifugeCtor,\n shared: SharedSubscription,\n attachmentEpoch: number,\n ): void {\n const client = this.#ensureClientForChannel(Centrifuge, shared.channel);\n\n const sub = client.newSubscription(\n shared.channel,\n this.#subscriptionOpts(Centrifuge, shared, attachmentEpoch),\n );\n shared.sub = sub;\n shared.client = client;\n\n sub.on(\"publication\", (ctx: PublicationContext) => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n for (const handler of shared.publicationHandlers) handler(ctx.data);\n });\n sub.on(\"subscribed\", () => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n const subscriptionEpoch = ++shared.subscriptionEpoch;\n for (const handler of shared.subscribedHandlers) handler(subscriptionEpoch);\n });\n sub.on(\"unsubscribed\", () => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n for (const handler of shared.unsubscribedHandlers) handler();\n });\n sub.on(\"error\", (ctx: SubscriptionErrorContext) => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n const sdkCtx = fromCentrifugeSubscriptionError(ctx);\n for (const handler of shared.errorHandlers) handler(sdkCtx);\n });\n\n sub.subscribe();\n }\n\n #getOrCreateSubscription(channel: string): SharedSubscription {\n const existing = this.#sharedSubs.get(channel);\n if (existing) return existing;\n\n const pending = this.#pendingTeardowns.get(channel);\n if (pending) {\n this.#pendingTeardowns.delete(channel);\n this.#sharedSubs.set(channel, pending);\n if (!pending.sub) {\n this.#attachSubscription(pending);\n } else if (pending.sub.state !== \"subscribed\") {\n pending.sub.subscribe();\n }\n return pending;\n }\n\n const shared: SharedSubscription = {\n channel,\n sub: null,\n client: null,\n attachmentEpoch: 0,\n consumers: 0,\n subscriptionEpoch: 0,\n publicationHandlers: new Set(),\n subscribedHandlers: new Set(),\n unsubscribedHandlers: new Set(),\n errorHandlers: new Set(),\n };\n\n this.#sharedSubs.set(channel, shared);\n try {\n this.#attachSubscription(shared);\n } catch (error) {\n this.#sharedSubs.delete(channel);\n throw error;\n }\n return shared;\n }\n\n #callErrorHandler(handler: ErrorHandler | undefined, ctx: SdkSubscriptionErrorContext): void {\n if (!handler) return;\n\n try {\n handler(ctx);\n } catch {\n // Keep error reporting isolated from other subscription consumers.\n }\n }\n\n #callConsumerHandler(\n channel: string,\n type: string,\n handler: () => void,\n onError?: ErrorHandler,\n ): void {\n try {\n handler();\n } catch (error) {\n this.#callErrorHandler(\n onError,\n createSdkSubscriptionErrorContext(channel, type, error),\n );\n }\n }\n\n #teardownSubscription(shared: SharedSubscription): void {\n const sub = shared.sub;\n const client = shared.client;\n const kind = this.#channelKind(shared.channel);\n shared.sub = null;\n shared.client = null;\n shared.attachmentEpoch++;\n if (!sub) return;\n\n try {\n if (sub.state !== \"unsubscribed\") {\n sub.unsubscribe();\n }\n } catch {\n // noop\n }\n try {\n client?.removeSubscription?.(sub);\n } catch {\n // noop\n }\n this.#disconnectClientIfIdle(kind);\n }\n\n #hasChannelsForKind(kind: RealtimeClientKind): boolean {\n for (const shared of this.#sharedSubs.values()) {\n if (this.#channelKind(shared.channel) === kind) return true;\n }\n for (const shared of this.#pendingTeardowns.values()) {\n if (this.#channelKind(shared.channel) === kind) return true;\n }\n return false;\n }\n\n #disconnectClientIfIdle(kind: RealtimeClientKind): void {\n if (this.#hasChannelsForKind(kind)) return;\n\n const client = kind === \"private\" ? this.#privateClient : this.#publicClient;\n if (kind === \"private\") {\n this.#privateClient = null;\n } else {\n this.#publicClient = null;\n }\n\n try {\n client?.disconnect();\n } catch {\n // noop\n }\n }\n\n #disconnect(): void {\n const publicClient = this.#publicClient;\n const privateClient = this.#privateClient;\n\n this.#pendingTeardowns.clear();\n this.#sharedSubs.clear();\n this.#publicClient = null;\n this.#privateClient = null;\n\n try {\n publicClient?.disconnect();\n } catch {\n // noop\n }\n try {\n privateClient?.disconnect();\n } catch {\n // noop\n }\n this.#connectionHandlers.clear();\n }\n\n #disconnectPrivate(): void {\n const privateClient = this.#privateClient;\n this.#privateClient = null;\n\n for (const [channel, shared] of this.#sharedSubs) {\n if (this.#channelKind(channel) !== \"private\") continue;\n this.#sharedSubs.delete(channel);\n this.#teardownSubscription(shared);\n }\n for (const [channel, shared] of this.#pendingTeardowns) {\n if (this.#channelKind(channel) !== \"private\") continue;\n this.#pendingTeardowns.delete(channel);\n this.#teardownSubscription(shared);\n }\n\n try {\n privateClient?.disconnect();\n } catch {\n // noop\n }\n }\n\n /**\n * Subscribes to a realtime channel and returns an unsubscribe function. Missing\n * authentication is reported to `onError`, or thrown synchronously when no error\n * observer is provided. Non-retryable token failures stop automatic retries;\n * calling subscribe again after correcting the failure restarts private realtime.\n */\n subscribe<T>(channel: string, handlers: SubscribeHandlers<T>): () => void {\n let shared: SharedSubscription;\n try {\n shared = this.#getOrCreateSubscription(channel);\n } catch (error) {\n if (!(error instanceof AuthenticationError)) throw error;\n if (!handlers.onError) throw error;\n\n const ctx = createSdkSubscriptionErrorContext(channel, \"auth\", error);\n queueMicrotask(() => this.#callErrorHandler(handlers.onError, ctx));\n return () => {};\n }\n shared.consumers++;\n\n const publicationHandler = handlers.onPublication;\n const errorHandler = handlers.onError;\n const subscribedHandler = handlers.onSubscribed;\n const unsubscribedHandler = handlers.onUnsubscribed;\n\n const onError: ErrorHandler | undefined = errorHandler\n ? (ctx) => this.#callErrorHandler(errorHandler, ctx)\n : undefined;\n const onPub: PublicationHandler = (data) => {\n this.#callConsumerHandler(\n channel,\n \"publication_handler\",\n () => publicationHandler(data as T),\n onError,\n );\n };\n let lastSubscribedEpoch = -1;\n const onSubscribed = subscribedHandler\n ? (subscriptionEpoch: number) => {\n if (subscriptionEpoch <= lastSubscribedEpoch) return;\n lastSubscribedEpoch = subscriptionEpoch;\n this.#callConsumerHandler(\n channel,\n \"subscribed_handler\",\n subscribedHandler,\n onError,\n );\n }\n : undefined;\n const onUnsubscribed = unsubscribedHandler\n ? () =>\n this.#callConsumerHandler(\n channel,\n \"unsubscribed_handler\",\n unsubscribedHandler,\n onError,\n )\n : undefined;\n\n shared.publicationHandlers.add(onPub);\n\n if (onSubscribed) shared.subscribedHandlers.add(onSubscribed);\n if (onUnsubscribed) shared.unsubscribedHandlers.add(onUnsubscribed);\n if (onError) shared.errorHandlers.add(onError);\n\n // Only an explicit subscribe restarts terminal private token failures.\n if (this.#channelKind(channel) === \"private\" && this.#hasAuth()) {\n if (shared.client?.state === \"disconnected\") shared.client.connect();\n if (shared.sub?.state === \"unsubscribed\") shared.sub.subscribe();\n }\n\n let closed = false;\n if (onSubscribed && shared.sub?.state === \"subscribed\") {\n const subscriptionEpoch = shared.subscriptionEpoch;\n queueMicrotask(() => {\n if (closed || shared.sub?.state !== \"subscribed\") return;\n onSubscribed(subscriptionEpoch);\n });\n }\n\n return () => {\n if (closed) return;\n closed = true;\n\n shared.publicationHandlers.delete(onPub);\n if (onSubscribed) shared.subscribedHandlers.delete(onSubscribed);\n if (onUnsubscribed) shared.unsubscribedHandlers.delete(onUnsubscribed);\n if (onError) shared.errorHandlers.delete(onError);\n\n shared.consumers--;\n if (shared.consumers <= 0) {\n const currentShared = this.#sharedSubs.get(channel);\n if (currentShared !== shared) return;\n\n this.#sharedSubs.delete(channel);\n this.#pendingTeardowns.set(channel, shared);\n\n queueMicrotask(() => {\n if (this.#pendingTeardowns.get(channel) !== shared) return;\n this.#pendingTeardowns.delete(channel);\n\n this.#teardownSubscription(shared);\n\n if (this.#sharedSubs.size === 0 && this.#pendingTeardowns.size === 0) {\n this.#disconnect();\n }\n });\n }\n };\n }\n\n /**\n * Connects to a realtime channel with a custom message decoder.\n */\n connectChannel<T extends DescMessage>(params: ConnectChannelParams<T>): () => void {\n return this.subscribe<Uint8Array>(params.channel, {\n onPublication: (data) => {\n let decoded: MessageShape<T>;\n try {\n decoded = fromBinary(params.schema, data);\n } catch (error) {\n this.#callErrorHandler(\n params.onError,\n createSdkSubscriptionErrorContext(params.channel, \"decode\", error),\n );\n return;\n }\n params.onPublication(decoded);\n },\n onSubscribed: params.onConnected,\n onUnsubscribed: params.onDisconnected,\n onError: params.onError,\n });\n }\n\n /**\n * Connects to a realtime channel that emits protobuf messages.\n */\n connectProtoChannel<T extends DescMessage>(params: ConnectChannelParams<T>): () => void {\n return this.subscribe<Uint8Array | MessageShape<T>>(params.channel, {\n onPublication: (data) => {\n let msg: MessageShape<T> | null;\n try {\n msg = decodeProtoFrame(params.schema, data);\n } catch (error) {\n this.#callErrorHandler(\n params.onError,\n createSdkSubscriptionErrorContext(params.channel, \"decode\", error),\n );\n return;\n }\n if (!msg) {\n this.#callErrorHandler(\n params.onError,\n createSdkSubscriptionErrorContext(\n params.channel,\n \"decode\",\n \"Unable to decode protobuf frame\",\n ),\n );\n return;\n }\n params.onPublication(msg);\n },\n onSubscribed: params.onConnected,\n onUnsubscribed: params.onDisconnected,\n onError: params.onError,\n });\n }\n\n /**\n * Disconnects the realtime client from all active channels.\n */\n disconnect(): void {\n this.#disconnect();\n }\n\n /**\n * Disconnects authenticated realtime state without touching public channels.\n */\n disconnectPrivate(): void {\n this.#disconnectPrivate();\n }\n\n get isConnected(): boolean {\n return this.#publicClient !== null || this.#privateClient !== null;\n }\n\n get activeChannels(): number {\n return this.#sharedSubs.size;\n }\n\n get totalConsumers(): number {\n let total = 0;\n for (const shared of this.#sharedSubs.values()) {\n total += shared.consumers;\n }\n return total;\n }\n}\n"],"mappings":";;;;;;AAuBA,MAAM,gBAAgB,UAAU;AAKhC,MAAM,sCACF,OAAO;AAMX,IAAI,wBAAwD;AAC5D,IAAI,uBAA8C;AAClD,IAAI,yBAAyB;AAa7B,SAAS,iBAA0C;CAC/C,IACI,2BAA2B,iCAC1B,YAA4C,KAAK,KAElD,OAAO,QAAQ,uBAAO,IAAI,MAAM,qDAAqD,CAAC;CAG1F,IAAI,CAAC,uBAAuB;EAExB,MAAM,gBADc,QAAQ,QAAQ,CAAC,CAAC,KAAK,sBACX,CAAC,CAAC,MAC7B,QAAQ;GACL,uBAAuB,IAAI;GAC3B,OAAO,IAAI;EACf,IACC,UAAU;GACP,IAAI,0BAA0B,eAAe,wBAAwB;GACrE,MAAM;EACV,CACJ;EACA,wBAAwB;CAC5B;CACA,OAAO;AACX;;;;AA8CA,IAAa,iBAAb,MAAyD;CACrD,gBAAmC;CACnC,iBAAoC;CACpC,sCAAsB,IAAI,IAAuB;CACjD,8BAAc,IAAI,IAAgC;CAClD,oCAAoB,IAAI,IAAgC;CACxD;CAEA,YAAY,QAAwB;EAChC,KAAKA,UAAU;GACX,OAAO,OAAO;GACd,eAAe,OAAO;GACtB,mBAAmB,OAAO;GAC1B,gBAAgB,OAAO,0BAA0B,CAAC;GAClD,SAAS,OAAO,kBAAkB;EACtC;CACJ;CAEA,MAAMC,gBAAgB,SAAoD;EACtE,OAAO,KAAKD,QAAQ,eAAe,OAAO;CAC9C;CAEA,uBAAuB,QAA4B,MAAc,OAAsB;EACnF,MAAM,MAAM,kCAAkC,OAAO,SAAS,MAAM,KAAK;EACzE,KAAK,MAAM,WAAW,OAAO,eACzB,QAAQ,GAAG;CAEnB;CAEA,0BAA0B,OAAsB;EAC5C,KAAK,MAAM,UAAU,KAAKE,YAAY,OAAO,GACzC,IAAI,KAAKC,aAAa,OAAO,OAAO,MAAM,WACtC,KAAKC,uBAAuB,QAAQ,oBAAoB,KAAK;CAGzE;CAEA,kBACI,YACA,QACA,iBACF;EACE,IAAI,KAAKD,aAAa,OAAO,OAAO,MAAM,WAAW,OAAO,KAAA;EAC5D,OAAO,EACH,UAAU,YAAY;GAClB,IAAI;IACA,MAAM,MAAM,IAAI,IAAI,KAAKH,QAAQ,iBAAiB;IAClD,IAAI,aAAa,IAAI,WAAW,OAAO,OAAO;IAC9C,MAAM,UAAU,MAAM,KAAKC,gBAAgB;KAAE;KAAK,QAAQ;IAAM,CAAC;IACjE,MAAM,MAAM,MAAM,cAAc,KAAK,EAAE,QAAQ,CAAC;IAChD,IAAI,CAAC,IAAI,IACL,MAAM,oBACF,IAAI,QACJ,uCAAuC,IAAI,QAC/C;IAEJ,MAAM,OAAQ,MAAM,IAAI,KAAK;IAC7B,IAAI,CAAC,MAAM,OACP,MAAM,IAAI,oBAAoB,0CAA0C;IAE5E,OAAO,KAAK;GAChB,SAAS,OAAO;IACZ,IAAI,OAAO,oBAAoB,iBAC3B,KAAKG,uBAAuB,QAAQ,sBAAsB,KAAK;IAEnE,IAAI,iBAAiB,kBAAkB,CAAC,MAAM,WAC1C,MAAM,IAAI,WAAW,kBAAkB,MAAM,OAAO;IAExD,MAAM;GACV;EACJ,EACJ;CACJ;CAEA,WAAoB;EAChB,OAAO,KAAKJ,QAAQ,QAAQ;CAChC;CAEA,aAAa,SAAqC;EAC9C,OAAO,QAAQ,WAAW,UAAU,IAAI,YAAY;CACxD;CAEA,oBAAoB,YAAwC;EACxD,MAAM,SAAS,IAAI,WAAW,KAAKA,QAAQ,KAAK;EAChD,KAAKK,gBAAgB;EAErB,OAAO,GAAG,mBAAmB;GACzB,IAAI,KAAKA,kBAAkB,QAAQ;GACnC,KAAK,MAAM,KAAK,KAAKC,qBAAqB,EAAE,cAAc;EAC9D,CAAC;EACD,OAAO,GAAG,sBAAsB;GAC5B,IAAI,KAAKD,kBAAkB,QAAQ;GACnC,KAAK,MAAM,KAAK,KAAKC,qBAAqB,EAAE,iBAAiB;EACjE,CAAC;EAED,OAAO,QAAQ;EACf,OAAO;CACX;CAEA,qBAAqB,YAAwC;EACzD,IAAI;EAkCJ,SAAS,IAAI,WAAW,KAAKN,QAAQ,OAAO,EAhCxC,UAAU,YAAY;GAClB,IAAI;IACA,MAAM,UAAU,MAAM,KAAKC,gBAAgB;KACvC,KAAK,KAAKD,QAAQ;KAClB,QAAQ;IACZ,CAAC;IACD,MAAM,MAAM,MAAM,cAAc,KAAKA,QAAQ,eAAe,EACxD,QACJ,CAAC;IACD,IAAI,CAAC,IAAI,IACL,MAAM,oBACF,IAAI,QACJ,qCAAqC,IAAI,QAC7C;IAEJ,MAAM,OAAQ,MAAM,IAAI,KAAK;IAC7B,IAAI,CAAC,MAAM,OACP,MAAM,IAAI,oBAAoB,wCAAwC;IAE1E,OAAO,KAAK;GAChB,SAAS,OAAO;IACZ,IAAI,KAAKO,mBAAmB,QACxB,KAAKC,0BAA0B,KAAK;IAExC,IAAI,iBAAiB,kBAAkB,CAAC,MAAM,WAC1C,MAAM,IAAI,WAAW,kBAAkB,MAAM,OAAO;IAExD,MAAM;GACV;EACJ,EAG2C,CAAC;EAChD,KAAKD,iBAAiB;EAEtB,OAAO,GAAG,mBAAmB;GACzB,IAAI,KAAKA,mBAAmB,QAAQ;GACpC,KAAK,MAAM,KAAK,KAAKD,qBAAqB,EAAE,cAAc;EAC9D,CAAC;EACD,OAAO,GAAG,sBAAsB;GAC5B,IAAI,KAAKC,mBAAmB,QAAQ;GACpC,KAAK,MAAM,KAAK,KAAKD,qBAAqB,EAAE,iBAAiB;EACjE,CAAC;EAED,OAAO,QAAQ;EACf,OAAO;CACX;CAEA,oBAAoB,YAAwC;EACxD,OAAO,KAAKD,iBAAiB,KAAKI,oBAAoB,UAAU;CACpE;CAEA,qBAAqB,YAAwC;EACzD,IAAI,CAAC,KAAKC,SAAS,GACf,MAAM,IAAI,oBACN,oEACJ;EAEJ,OAAO,KAAKH,kBAAkB,KAAKI,qBAAqB,UAAU;CACtE;CAEA,mBAAmB,SAAuB;EACtC,IAAI,KAAKR,aAAa,OAAO,MAAM,aAAa,CAAC,KAAKO,SAAS,GAC3D,MAAM,IAAI,oBACN,wCAAwC,QAAQ,yBACpD;CAER;CAEA,wBAAwB,YAA4B,SAA6B;EAC7E,KAAKE,mBAAmB,OAAO;EAC/B,IAAI,KAAKT,aAAa,OAAO,MAAM,WAC/B,OAAO,KAAKU,qBAAqB,UAAU;EAG/C,OAAO,KAAKC,oBAAoB,UAAU;CAC9C;CAEA,oBAAoB,QAAkC;EAClD,IAAI,OAAO,KAAK;EAIhB,KAAKF,mBAAmB,OAAO,OAAO;EAEtC,MAAM,kBAAkB,OAAO,kBAAkB;EACjD,OAAO,kBAAkB;EAIzB,IAAI,sBAAsB;GACtB,KAAKG,uBAAuB,sBAAsB,QAAQ,eAAe;GACzE;EACJ;EACA,KAAUC,8BAA8B,QAAQ,eAAe;CACnE;CAEA,MAAMA,8BACF,QACA,iBACa;EACb,IAAI;EACJ,IAAI;GACA,aAAa,MAAM,eAAe;EACtC,SAAS,OAAO;GACZ,IAAI,OAAO,oBAAoB,iBAAiB;GAChD,IAAI,KAAKd,YAAY,IAAI,OAAO,OAAO,MAAM,QACzC,KAAKA,YAAY,OAAO,OAAO,OAAO;GAE1C,KAAKE,uBAAuB,QAAQ,kBAAkB,KAAK;GAC3D;EACJ;EAIA,IAAI,OAAO,oBAAoB,mBAAmB,OAAO,KAAK;EAC9D,IAAI,KAAKF,YAAY,IAAI,OAAO,OAAO,MAAM,QAAQ;EAErD,IAAI;GACA,KAAKa,uBAAuB,YAAY,QAAQ,eAAe;EACnE,SAAS,OAAO;GACZ,KAAKb,YAAY,OAAO,OAAO,OAAO;GACtC,KAAKE,uBAAuB,QAAQ,QAAQ,KAAK;EACrD;CACJ;CAEA,uBACI,YACA,QACA,iBACI;EACJ,MAAM,SAAS,KAAKa,wBAAwB,YAAY,OAAO,OAAO;EAEtE,MAAM,MAAM,OAAO,gBACf,OAAO,SACP,KAAKC,kBAAkB,YAAY,QAAQ,eAAe,CAC9D;EACA,OAAO,MAAM;EACb,OAAO,SAAS;EAEhB,IAAI,GAAG,gBAAgB,QAA4B;GAC/C,IAAI,OAAO,QAAQ,OAAO,OAAO,oBAAoB,iBAAiB;GACtE,KAAK,MAAM,WAAW,OAAO,qBAAqB,QAAQ,IAAI,IAAI;EACtE,CAAC;EACD,IAAI,GAAG,oBAAoB;GACvB,IAAI,OAAO,QAAQ,OAAO,OAAO,oBAAoB,iBAAiB;GACtE,MAAM,oBAAoB,EAAE,OAAO;GACnC,KAAK,MAAM,WAAW,OAAO,oBAAoB,QAAQ,iBAAiB;EAC9E,CAAC;EACD,IAAI,GAAG,sBAAsB;GACzB,IAAI,OAAO,QAAQ,OAAO,OAAO,oBAAoB,iBAAiB;GACtE,KAAK,MAAM,WAAW,OAAO,sBAAsB,QAAQ;EAC/D,CAAC;EACD,IAAI,GAAG,UAAU,QAAkC;GAC/C,IAAI,OAAO,QAAQ,OAAO,OAAO,oBAAoB,iBAAiB;GACtE,MAAM,SAAS,gCAAgC,GAAG;GAClD,KAAK,MAAM,WAAW,OAAO,eAAe,QAAQ,MAAM;EAC9D,CAAC;EAED,IAAI,UAAU;CAClB;CAEA,yBAAyB,SAAqC;EAC1D,MAAM,WAAW,KAAKhB,YAAY,IAAI,OAAO;EAC7C,IAAI,UAAU,OAAO;EAErB,MAAM,UAAU,KAAKiB,kBAAkB,IAAI,OAAO;EAClD,IAAI,SAAS;GACT,KAAKA,kBAAkB,OAAO,OAAO;GACrC,KAAKjB,YAAY,IAAI,SAAS,OAAO;GACrC,IAAI,CAAC,QAAQ,KACT,KAAKkB,oBAAoB,OAAO;QAC7B,IAAI,QAAQ,IAAI,UAAU,cAC7B,QAAQ,IAAI,UAAU;GAE1B,OAAO;EACX;EAEA,MAAM,SAA6B;GAC/B;GACA,KAAK;GACL,QAAQ;GACR,iBAAiB;GACjB,WAAW;GACX,mBAAmB;GACnB,qCAAqB,IAAI,IAAI;GAC7B,oCAAoB,IAAI,IAAI;GAC5B,sCAAsB,IAAI,IAAI;GAC9B,+BAAe,IAAI,IAAI;EAC3B;EAEA,KAAKlB,YAAY,IAAI,SAAS,MAAM;EACpC,IAAI;GACA,KAAKkB,oBAAoB,MAAM;EACnC,SAAS,OAAO;GACZ,KAAKlB,YAAY,OAAO,OAAO;GAC/B,MAAM;EACV;EACA,OAAO;CACX;CAEA,kBAAkB,SAAmC,KAAwC;EACzF,IAAI,CAAC,SAAS;EAEd,IAAI;GACA,QAAQ,GAAG;EACf,QAAQ,CAER;CACJ;CAEA,qBACI,SACA,MACA,SACA,SACI;EACJ,IAAI;GACA,QAAQ;EACZ,SAAS,OAAO;GACZ,KAAKmB,kBACD,SACA,kCAAkC,SAAS,MAAM,KAAK,CAC1D;EACJ;CACJ;CAEA,sBAAsB,QAAkC;EACpD,MAAM,MAAM,OAAO;EACnB,MAAM,SAAS,OAAO;EACtB,MAAM,OAAO,KAAKlB,aAAa,OAAO,OAAO;EAC7C,OAAO,MAAM;EACb,OAAO,SAAS;EAChB,OAAO;EACP,IAAI,CAAC,KAAK;EAEV,IAAI;GACA,IAAI,IAAI,UAAU,gBACd,IAAI,YAAY;EAExB,QAAQ,CAER;EACA,IAAI;GACA,QAAQ,qBAAqB,GAAG;EACpC,QAAQ,CAER;EACA,KAAKmB,wBAAwB,IAAI;CACrC;CAEA,oBAAoB,MAAmC;EACnD,KAAK,MAAM,UAAU,KAAKpB,YAAY,OAAO,GACzC,IAAI,KAAKC,aAAa,OAAO,OAAO,MAAM,MAAM,OAAO;EAE3D,KAAK,MAAM,UAAU,KAAKgB,kBAAkB,OAAO,GAC/C,IAAI,KAAKhB,aAAa,OAAO,OAAO,MAAM,MAAM,OAAO;EAE3D,OAAO;CACX;CAEA,wBAAwB,MAAgC;EACpD,IAAI,KAAKoB,oBAAoB,IAAI,GAAG;EAEpC,MAAM,SAAS,SAAS,YAAY,KAAKhB,iBAAiB,KAAKF;EAC/D,IAAI,SAAS,WACT,KAAKE,iBAAiB;OAEtB,KAAKF,gBAAgB;EAGzB,IAAI;GACA,QAAQ,WAAW;EACvB,QAAQ,CAER;CACJ;CAEA,cAAoB;EAChB,MAAM,eAAe,KAAKA;EAC1B,MAAM,gBAAgB,KAAKE;EAE3B,KAAKY,kBAAkB,MAAM;EAC7B,KAAKjB,YAAY,MAAM;EACvB,KAAKG,gBAAgB;EACrB,KAAKE,iBAAiB;EAEtB,IAAI;GACA,cAAc,WAAW;EAC7B,QAAQ,CAER;EACA,IAAI;GACA,eAAe,WAAW;EAC9B,QAAQ,CAER;EACA,KAAKD,oBAAoB,MAAM;CACnC;CAEA,qBAA2B;EACvB,MAAM,gBAAgB,KAAKC;EAC3B,KAAKA,iBAAiB;EAEtB,KAAK,MAAM,CAAC,SAAS,WAAW,KAAKL,aAAa;GAC9C,IAAI,KAAKC,aAAa,OAAO,MAAM,WAAW;GAC9C,KAAKD,YAAY,OAAO,OAAO;GAC/B,KAAKsB,sBAAsB,MAAM;EACrC;EACA,KAAK,MAAM,CAAC,SAAS,WAAW,KAAKL,mBAAmB;GACpD,IAAI,KAAKhB,aAAa,OAAO,MAAM,WAAW;GAC9C,KAAKgB,kBAAkB,OAAO,OAAO;GACrC,KAAKK,sBAAsB,MAAM;EACrC;EAEA,IAAI;GACA,eAAe,WAAW;EAC9B,QAAQ,CAER;CACJ;;;;;;;CAQA,UAAa,SAAiB,UAA4C;EACtE,IAAI;EACJ,IAAI;GACA,SAAS,KAAKC,yBAAyB,OAAO;EAClD,SAAS,OAAO;GACZ,IAAI,EAAE,iBAAiB,sBAAsB,MAAM;GACnD,IAAI,CAAC,SAAS,SAAS,MAAM;GAE7B,MAAM,MAAM,kCAAkC,SAAS,QAAQ,KAAK;GACpE,qBAAqB,KAAKJ,kBAAkB,SAAS,SAAS,GAAG,CAAC;GAClE,aAAa,CAAC;EAClB;EACA,OAAO;EAEP,MAAM,qBAAqB,SAAS;EACpC,MAAM,eAAe,SAAS;EAC9B,MAAM,oBAAoB,SAAS;EACnC,MAAM,sBAAsB,SAAS;EAErC,MAAM,UAAoC,gBACnC,QAAQ,KAAKA,kBAAkB,cAAc,GAAG,IACjD,KAAA;EACN,MAAM,SAA6B,SAAS;GACxC,KAAKK,qBACD,SACA,6BACM,mBAAmB,IAAS,GAClC,OACJ;EACJ;EACA,IAAI,sBAAsB;EAC1B,MAAM,eAAe,qBACd,sBAA8B;GAC3B,IAAI,qBAAqB,qBAAqB;GAC9C,sBAAsB;GACtB,KAAKA,qBACD,SACA,sBACA,mBACA,OACJ;EACJ,IACA,KAAA;EACN,MAAM,iBAAiB,4BAEb,KAAKA,qBACD,SACA,wBACA,qBACA,OACJ,IACJ,KAAA;EAEN,OAAO,oBAAoB,IAAI,KAAK;EAEpC,IAAI,cAAc,OAAO,mBAAmB,IAAI,YAAY;EAC5D,IAAI,gBAAgB,OAAO,qBAAqB,IAAI,cAAc;EAClE,IAAI,SAAS,OAAO,cAAc,IAAI,OAAO;EAG7C,IAAI,KAAKvB,aAAa,OAAO,MAAM,aAAa,KAAKO,SAAS,GAAG;GAC7D,IAAI,OAAO,QAAQ,UAAU,gBAAgB,OAAO,OAAO,QAAQ;GACnE,IAAI,OAAO,KAAK,UAAU,gBAAgB,OAAO,IAAI,UAAU;EACnE;EAEA,IAAI,SAAS;EACb,IAAI,gBAAgB,OAAO,KAAK,UAAU,cAAc;GACpD,MAAM,oBAAoB,OAAO;GACjC,qBAAqB;IACjB,IAAI,UAAU,OAAO,KAAK,UAAU,cAAc;IAClD,aAAa,iBAAiB;GAClC,CAAC;EACL;EAEA,aAAa;GACT,IAAI,QAAQ;GACZ,SAAS;GAET,OAAO,oBAAoB,OAAO,KAAK;GACvC,IAAI,cAAc,OAAO,mBAAmB,OAAO,YAAY;GAC/D,IAAI,gBAAgB,OAAO,qBAAqB,OAAO,cAAc;GACrE,IAAI,SAAS,OAAO,cAAc,OAAO,OAAO;GAEhD,OAAO;GACP,IAAI,OAAO,aAAa,GAAG;IAEvB,IADsB,KAAKR,YAAY,IAAI,OAC3B,MAAM,QAAQ;IAE9B,KAAKA,YAAY,OAAO,OAAO;IAC/B,KAAKiB,kBAAkB,IAAI,SAAS,MAAM;IAE1C,qBAAqB;KACjB,IAAI,KAAKA,kBAAkB,IAAI,OAAO,MAAM,QAAQ;KACpD,KAAKA,kBAAkB,OAAO,OAAO;KAErC,KAAKK,sBAAsB,MAAM;KAEjC,IAAI,KAAKtB,YAAY,SAAS,KAAK,KAAKiB,kBAAkB,SAAS,GAC/D,KAAKQ,YAAY;IAEzB,CAAC;GACL;EACJ;CACJ;;;;CAKA,eAAsC,QAA6C;EAC/E,OAAO,KAAK,UAAsB,OAAO,SAAS;GAC9C,gBAAgB,SAAS;IACrB,IAAI;IACJ,IAAI;KACA,UAAU,WAAW,OAAO,QAAQ,IAAI;IAC5C,SAAS,OAAO;KACZ,KAAKN,kBACD,OAAO,SACP,kCAAkC,OAAO,SAAS,UAAU,KAAK,CACrE;KACA;IACJ;IACA,OAAO,cAAc,OAAO;GAChC;GACA,cAAc,OAAO;GACrB,gBAAgB,OAAO;GACvB,SAAS,OAAO;EACpB,CAAC;CACL;;;;CAKA,oBAA2C,QAA6C;EACpF,OAAO,KAAK,UAAwC,OAAO,SAAS;GAChE,gBAAgB,SAAS;IACrB,IAAI;IACJ,IAAI;KACA,MAAM,iBAAiB,OAAO,QAAQ,IAAI;IAC9C,SAAS,OAAO;KACZ,KAAKA,kBACD,OAAO,SACP,kCAAkC,OAAO,SAAS,UAAU,KAAK,CACrE;KACA;IACJ;IACA,IAAI,CAAC,KAAK;KACN,KAAKA,kBACD,OAAO,SACP,kCACI,OAAO,SACP,UACA,iCACJ,CACJ;KACA;IACJ;IACA,OAAO,cAAc,GAAG;GAC5B;GACA,cAAc,OAAO;GACrB,gBAAgB,OAAO;GACvB,SAAS,OAAO;EACpB,CAAC;CACL;;;;CAKA,aAAmB;EACf,KAAKM,YAAY;CACrB;;;;CAKA,oBAA0B;EACtB,KAAKC,mBAAmB;CAC5B;CAEA,IAAI,cAAuB;EACvB,OAAO,KAAKvB,kBAAkB,QAAQ,KAAKE,mBAAmB;CAClE;CAEA,IAAI,iBAAyB;EACzB,OAAO,KAAKL,YAAY;CAC5B;CAEA,IAAI,iBAAyB;EACzB,IAAI,QAAQ;EACZ,KAAK,MAAM,UAAU,KAAKA,YAAY,OAAO,GACzC,SAAS,OAAO;EAEpB,OAAO;CACX;AACJ"}
1
+ {"version":3,"file":"client.js","names":["#config","#getAuthHeaders","#sharedSubs","#channelKind","#emitSubscriptionError","#publicClient","#terminateSubscriptions","#pendingTeardowns","#privateClient","#emitConnectionTokenError","#createPublicClient","#hasAuth","#createPrivateClient","#ensurePublicClient","#assertChannelAuth","#attachSubscriptionNow","#attachSubscriptionWhenLoaded","#ensureClientForChannel","#subscriptionOpts","#attachSubscription","#callErrorHandler","#teardownSubscription","#disconnectClientIfIdle","#hasChannelsForKind","#getOrCreateSubscription","#callConsumerHandler","#disconnect","#disconnectPrivate"],"sources":["../../src/realtime/client.ts"],"sourcesContent":["import { fromBinary, type DescMessage, type MessageShape } from \"@bufbuild/protobuf\";\nimport type {\n Centrifuge,\n SubscriptionErrorContext,\n PublicationContext,\n Subscription,\n} from \"centrifuge/build/protobuf\";\nimport type * as CentrifugeModule from \"centrifuge/build/protobuf\";\nimport {\n createSdkSubscriptionErrorContext,\n fromCentrifugeSubscriptionError,\n type SdkSubscriptionErrorContext,\n} from \"../shared/subscription-errors.js\";\nimport {\n AuthenticationError,\n errorFromHttpStatus,\n InternalServerError,\n PolyesterError,\n} from \"../shared/errors.js\";\nimport { makeFetch } from \"../shared/transports.js\";\nimport { decodeProtoFrame } from \"../utils/streams.js\";\nimport type { ConnectChannelParams, PolyesterRealtime, SubscribeHandlers } from \"./types.js\";\n\nconst realtimeFetch = makeFetch();\n\ntype CentrifugeCtor = typeof CentrifugeModule.Centrifuge;\ntype CentrifugeModuleLoader = () => Promise<typeof CentrifugeModule>;\n\nconst defaultCentrifugeModuleLoader: CentrifugeModuleLoader = () =>\n import(\"centrifuge/build/protobuf\");\n\n// Centrifuge's protobuf build embeds the protobuf.js runtime (~300 KB minified).\n// Loading it lazily keeps it out of the eager module graph on both the server\n// (Cloudflare isolate cold start — SSR never opens a websocket) and the client\n// app shell; it is only fetched when the first subscription attaches.\nlet centrifugeCtorPromise: Promise<CentrifugeCtor> | null = null;\nlet loadedCentrifugeCtor: CentrifugeCtor | null = null;\nlet centrifugeModuleLoader = defaultCentrifugeModuleLoader;\nexport function __setRealtimeCentrifugeForTests(Centrifuge: CentrifugeCtor | null): void {\n loadedCentrifugeCtor = Centrifuge;\n centrifugeCtorPromise = Centrifuge ? Promise.resolve(Centrifuge) : null;\n}\n\n/** Replaces the lazy Centrifuge module loader for isolated transport-load tests. */\nexport function __setRealtimeCentrifugeLoaderForTests(loader: CentrifugeModuleLoader | null): void {\n centrifugeModuleLoader = loader ?? defaultCentrifugeModuleLoader;\n loadedCentrifugeCtor = null;\n centrifugeCtorPromise = null;\n}\n\nfunction loadCentrifuge(): Promise<CentrifugeCtor> {\n if (\n centrifugeModuleLoader === defaultCentrifugeModuleLoader &&\n (import.meta as { env?: { SSR?: boolean } }).env?.SSR\n ) {\n return Promise.reject(new Error(\"Realtime subscriptions are browser-only during SSR.\"));\n }\n\n if (!centrifugeCtorPromise) {\n const loadAttempt = Promise.resolve().then(centrifugeModuleLoader);\n const retryableLoad = loadAttempt.then(\n (mod) => {\n loadedCentrifugeCtor = mod.Centrifuge;\n return mod.Centrifuge;\n },\n (error) => {\n if (centrifugeCtorPromise === retryableLoad) centrifugeCtorPromise = null;\n throw error;\n },\n );\n centrifugeCtorPromise = retryableLoad;\n }\n return centrifugeCtorPromise;\n}\n\nexport interface RealtimeAuthRequest {\n url: string | URL;\n method: string;\n}\n\nexport interface RealtimeConfig {\n wsUrl: string;\n tokenEndpoint: string;\n subscribeEndpoint: string;\n getAuthHeaders?: (request: RealtimeAuthRequest) => Promise<HeadersInit> | HeadersInit;\n hasAuth?: () => boolean;\n}\n\ntype ResolvedRealtimeConfig = Pick<\n RealtimeConfig,\n \"wsUrl\" | \"tokenEndpoint\" | \"subscribeEndpoint\"\n> & {\n getAuthHeaders: (request: RealtimeAuthRequest) => Promise<HeadersInit> | HeadersInit;\n hasAuth: () => boolean;\n};\n\nexport type { ConnectChannelParams, PolyesterRealtime, SubscribeHandlers } from \"./types.js\";\n\ntype PublicationHandler<T = unknown> = (data: T) => void;\ntype ErrorHandler = (ctx: SdkSubscriptionErrorContext) => void;\ntype RealtimeClientKind = \"public\" | \"private\";\n\ninterface SharedSubscription {\n channel: string;\n sub: Subscription | null;\n client: Centrifuge | null;\n attachmentEpoch: number;\n consumers: number;\n subscriptionEpoch: number;\n publicationHandlers: Set<PublicationHandler>;\n subscribedHandlers: Set<(epoch: number) => void>;\n unsubscribedHandlers: Set<() => void>;\n errorHandlers: Set<ErrorHandler>;\n}\n\n/**\n * Shared Centrifuge realtime client that multiplexes public and private protobuf subscriptions across SDK services.\n */\nexport class RealtimeClient implements PolyesterRealtime {\n #publicClient: Centrifuge | null = null;\n #privateClient: Centrifuge | null = null;\n #sharedSubs = new Map<string, SharedSubscription>();\n #pendingTeardowns = new Map<string, SharedSubscription>();\n readonly #config: ResolvedRealtimeConfig;\n\n constructor(config: RealtimeConfig) {\n this.#config = {\n wsUrl: config.wsUrl,\n tokenEndpoint: config.tokenEndpoint,\n subscribeEndpoint: config.subscribeEndpoint,\n getAuthHeaders: config.getAuthHeaders ?? (() => ({})),\n hasAuth: config.hasAuth ?? (() => false),\n };\n }\n\n async #getAuthHeaders(request: RealtimeAuthRequest): Promise<HeadersInit> {\n return this.#config.getAuthHeaders(request);\n }\n\n #emitSubscriptionError(shared: SharedSubscription, type: string, error: unknown): void {\n const ctx = createSdkSubscriptionErrorContext(shared.channel, type, error);\n for (const handler of shared.errorHandlers) {\n handler(ctx);\n }\n }\n\n #emitConnectionTokenError(error: unknown): void {\n for (const shared of this.#sharedSubs.values()) {\n if (this.#channelKind(shared.channel) === \"private\") {\n this.#emitSubscriptionError(shared, \"connection_token\", error);\n }\n }\n }\n\n #subscriptionOpts(\n Centrifuge: CentrifugeCtor,\n shared: SharedSubscription,\n attachmentEpoch: number,\n ) {\n if (this.#channelKind(shared.channel) !== \"private\") return undefined;\n return {\n getToken: async () => {\n try {\n const url = new URL(this.#config.subscribeEndpoint);\n url.searchParams.set(\"channel\", shared.channel);\n const headers = await this.#getAuthHeaders({ url, method: \"GET\" });\n const res = await realtimeFetch(url, { headers });\n if (!res.ok) {\n throw errorFromHttpStatus(\n res.status,\n `Failed to fetch subscription token: ${res.status}`,\n );\n }\n const json = (await res.json()) as { token?: string };\n if (!json?.token) {\n throw new InternalServerError(\"Subscription token response had no token\");\n }\n return json.token;\n } catch (error) {\n if (shared.attachmentEpoch === attachmentEpoch) {\n this.#emitSubscriptionError(shared, \"subscription_token\", error);\n }\n if (error instanceof PolyesterError && !error.retryable) {\n throw new Centrifuge.UnauthorizedError(error.message);\n }\n throw error;\n }\n },\n };\n }\n\n #hasAuth(): boolean {\n return this.#config.hasAuth();\n }\n\n #channelKind(channel: string): RealtimeClientKind {\n return channel.startsWith(\"private:\") ? \"private\" : \"public\";\n }\n\n #createPublicClient(Centrifuge: CentrifugeCtor): Centrifuge {\n const client = new Centrifuge(this.#config.wsUrl);\n this.#publicClient = client;\n\n client.on(\"disconnected\", (ctx) => {\n // Codes 0 (disconnectCalled) and 1 (unauthorized) are handled elsewhere;\n // every other disconnected event is terminal.\n if (this.#publicClient !== client || ctx.code <= 1) return;\n this.#publicClient = null;\n this.#terminateSubscriptions(\n [...this.#sharedSubs.values(), ...this.#pendingTeardowns.values()].filter(\n (shared) => shared.client === client,\n ),\n \"disconnected\",\n ctx,\n );\n });\n\n client.connect();\n return client;\n }\n\n #createPrivateClient(Centrifuge: CentrifugeCtor): Centrifuge {\n let client: Centrifuge;\n const opts = {\n getToken: async () => {\n try {\n const headers = await this.#getAuthHeaders({\n url: this.#config.tokenEndpoint,\n method: \"GET\",\n });\n const res = await realtimeFetch(this.#config.tokenEndpoint, {\n headers,\n });\n if (!res.ok) {\n throw errorFromHttpStatus(\n res.status,\n `Failed to fetch connection token: ${res.status}`,\n );\n }\n const json = (await res.json()) as { token?: string };\n if (!json?.token) {\n throw new InternalServerError(\"Connection token response had no token\");\n }\n return json.token;\n } catch (error) {\n if (this.#privateClient === client) {\n this.#emitConnectionTokenError(error);\n }\n if (error instanceof PolyesterError && !error.retryable) {\n throw new Centrifuge.UnauthorizedError(error.message);\n }\n throw error;\n }\n },\n };\n\n client = new Centrifuge(this.#config.wsUrl, opts);\n this.#privateClient = client;\n\n client.on(\"disconnected\", (ctx) => {\n // Codes 0 (disconnectCalled) and 1 (unauthorized) are handled elsewhere;\n // every other disconnected event is terminal.\n if (this.#privateClient !== client || ctx.code <= 1) return;\n this.#privateClient = null;\n this.#terminateSubscriptions(\n [...this.#sharedSubs.values(), ...this.#pendingTeardowns.values()].filter(\n (shared) => shared.client === client,\n ),\n \"disconnected\",\n ctx,\n );\n });\n\n client.connect();\n return client;\n }\n\n #ensurePublicClient(Centrifuge: CentrifugeCtor): Centrifuge {\n return this.#publicClient ?? this.#createPublicClient(Centrifuge);\n }\n\n #assertChannelAuth(channel: string): void {\n if (this.#channelKind(channel) === \"private\" && !this.#hasAuth()) {\n throw new AuthenticationError(\n `Cannot subscribe to private channel \"${channel}\" without authentication`,\n );\n }\n }\n\n #ensureClientForChannel(Centrifuge: CentrifugeCtor, channel: string): Centrifuge {\n if (this.#channelKind(channel) === \"private\") {\n return this.#privateClient ?? this.#createPrivateClient(Centrifuge);\n }\n\n return this.#ensurePublicClient(Centrifuge);\n }\n\n #attachSubscription(shared: SharedSubscription): void {\n if (shared.sub) return;\n\n // Auth failures must surface synchronously to subscribe() callers, as\n // they did when centrifuge was imported statically.\n this.#assertChannelAuth(shared.channel);\n\n const attachmentEpoch = shared.attachmentEpoch + 1;\n shared.attachmentEpoch = attachmentEpoch;\n\n // Once the transport module is loaded, attachment stays fully\n // synchronous — only the very first attach pays the dynamic import.\n if (loadedCentrifugeCtor) {\n this.#attachSubscriptionNow(loadedCentrifugeCtor, shared, attachmentEpoch);\n return;\n }\n void this.#attachSubscriptionWhenLoaded(shared, attachmentEpoch);\n }\n\n async #attachSubscriptionWhenLoaded(\n shared: SharedSubscription,\n attachmentEpoch: number,\n ): Promise<void> {\n let Centrifuge: CentrifugeCtor;\n try {\n Centrifuge = await loadCentrifuge();\n } catch (error) {\n if (shared.attachmentEpoch !== attachmentEpoch) return;\n if (this.#sharedSubs.get(shared.channel) === shared) {\n this.#sharedSubs.delete(shared.channel);\n }\n this.#emitSubscriptionError(shared, \"transport_load\", error);\n return;\n }\n\n // The subscription may have been torn down or re-attached while the\n // transport module was loading.\n if (shared.attachmentEpoch !== attachmentEpoch || shared.sub) return;\n if (this.#sharedSubs.get(shared.channel) !== shared) return;\n\n try {\n this.#assertChannelAuth(shared.channel);\n this.#attachSubscriptionNow(Centrifuge, shared, attachmentEpoch);\n } catch (error) {\n this.#sharedSubs.delete(shared.channel);\n this.#emitSubscriptionError(shared, \"auth\", error);\n }\n }\n\n #attachSubscriptionNow(\n Centrifuge: CentrifugeCtor,\n shared: SharedSubscription,\n attachmentEpoch: number,\n ): void {\n const client = this.#ensureClientForChannel(Centrifuge, shared.channel);\n\n const sub = client.newSubscription(\n shared.channel,\n this.#subscriptionOpts(Centrifuge, shared, attachmentEpoch),\n );\n shared.sub = sub;\n shared.client = client;\n\n sub.on(\"publication\", (ctx: PublicationContext) => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n for (const handler of shared.publicationHandlers) handler(ctx.data);\n });\n sub.on(\"subscribed\", () => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n const subscriptionEpoch = ++shared.subscriptionEpoch;\n for (const handler of shared.subscribedHandlers) handler(subscriptionEpoch);\n });\n sub.on(\"unsubscribed\", (ctx) => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n if (ctx.code >= 2000 && ctx.code < 2500) {\n this.#terminateSubscriptions([shared], \"unsubscribed\", ctx);\n return;\n }\n for (const handler of shared.unsubscribedHandlers) handler();\n });\n sub.on(\"error\", (ctx: SubscriptionErrorContext) => {\n if (shared.sub !== sub || shared.attachmentEpoch !== attachmentEpoch) return;\n const sdkCtx = fromCentrifugeSubscriptionError(ctx);\n for (const handler of shared.errorHandlers) handler(sdkCtx);\n });\n\n sub.subscribe();\n }\n\n #getOrCreateSubscription(channel: string): SharedSubscription {\n const existing = this.#sharedSubs.get(channel);\n if (existing) return existing;\n\n const pending = this.#pendingTeardowns.get(channel);\n if (pending) {\n this.#pendingTeardowns.delete(channel);\n this.#sharedSubs.set(channel, pending);\n if (!pending.sub) {\n this.#attachSubscription(pending);\n } else if (pending.sub.state !== \"subscribed\") {\n pending.sub.subscribe();\n }\n return pending;\n }\n\n const shared: SharedSubscription = {\n channel,\n sub: null,\n client: null,\n attachmentEpoch: 0,\n consumers: 0,\n subscriptionEpoch: 0,\n publicationHandlers: new Set(),\n subscribedHandlers: new Set(),\n unsubscribedHandlers: new Set(),\n errorHandlers: new Set(),\n };\n\n this.#sharedSubs.set(channel, shared);\n try {\n this.#attachSubscription(shared);\n } catch (error) {\n this.#sharedSubs.delete(channel);\n throw error;\n }\n return shared;\n }\n\n #callErrorHandler(handler: ErrorHandler | undefined, ctx: SdkSubscriptionErrorContext): void {\n if (!handler) return;\n\n try {\n handler(ctx);\n } catch {\n // Keep error reporting isolated from other subscription consumers.\n }\n }\n\n #callConsumerHandler(\n channel: string,\n type: string,\n handler: () => void,\n onError?: ErrorHandler,\n ): void {\n try {\n handler();\n } catch (error) {\n this.#callErrorHandler(\n onError,\n createSdkSubscriptionErrorContext(channel, type, error),\n );\n }\n }\n\n #terminateSubscriptions(\n subscriptions: SharedSubscription[],\n type: \"disconnected\" | \"unsubscribed\",\n ctx: { code: number; reason: string },\n ): void {\n const notifications = subscriptions.map((shared) => ({\n error: createSdkSubscriptionErrorContext(shared.channel, type, {\n code: ctx.code,\n message: ctx.reason,\n }),\n errorHandlers: [...shared.errorHandlers],\n closeHandlers: [...shared.unsubscribedHandlers],\n }));\n\n // Finish cleanup for every affected channel before callbacks can resubscribe.\n for (const shared of subscriptions) {\n if (this.#sharedSubs.get(shared.channel) === shared) {\n this.#sharedSubs.delete(shared.channel);\n }\n if (this.#pendingTeardowns.get(shared.channel) === shared) {\n this.#pendingTeardowns.delete(shared.channel);\n }\n this.#teardownSubscription(shared);\n shared.publicationHandlers.clear();\n shared.subscribedHandlers.clear();\n shared.unsubscribedHandlers.clear();\n shared.errorHandlers.clear();\n }\n\n for (const { error, errorHandlers, closeHandlers } of notifications) {\n for (const handler of errorHandlers) handler(error);\n for (const handler of closeHandlers) handler();\n }\n }\n\n #teardownSubscription(shared: SharedSubscription): void {\n const sub = shared.sub;\n const client = shared.client;\n const kind = this.#channelKind(shared.channel);\n shared.sub = null;\n shared.client = null;\n shared.attachmentEpoch++;\n if (!sub) return;\n\n try {\n if (sub.state !== \"unsubscribed\") {\n sub.unsubscribe();\n }\n } catch {\n // noop\n }\n try {\n client?.removeSubscription?.(sub);\n } catch {\n // noop\n }\n this.#disconnectClientIfIdle(kind);\n }\n\n #hasChannelsForKind(kind: RealtimeClientKind): boolean {\n for (const shared of this.#sharedSubs.values()) {\n if (this.#channelKind(shared.channel) === kind) return true;\n }\n for (const shared of this.#pendingTeardowns.values()) {\n if (this.#channelKind(shared.channel) === kind) return true;\n }\n return false;\n }\n\n #disconnectClientIfIdle(kind: RealtimeClientKind): void {\n if (this.#hasChannelsForKind(kind)) return;\n\n const client = kind === \"private\" ? this.#privateClient : this.#publicClient;\n if (kind === \"private\") {\n this.#privateClient = null;\n } else {\n this.#publicClient = null;\n }\n\n try {\n client?.disconnect();\n } catch {\n // noop\n }\n }\n\n #disconnect(): void {\n const publicClient = this.#publicClient;\n const privateClient = this.#privateClient;\n\n this.#pendingTeardowns.clear();\n this.#sharedSubs.clear();\n this.#publicClient = null;\n this.#privateClient = null;\n\n try {\n publicClient?.disconnect();\n } catch {\n // noop\n }\n try {\n privateClient?.disconnect();\n } catch {\n // noop\n }\n }\n\n #disconnectPrivate(): void {\n const privateClient = this.#privateClient;\n this.#privateClient = null;\n\n for (const [channel, shared] of this.#sharedSubs) {\n if (this.#channelKind(channel) !== \"private\") continue;\n this.#sharedSubs.delete(channel);\n this.#teardownSubscription(shared);\n }\n for (const [channel, shared] of this.#pendingTeardowns) {\n if (this.#channelKind(channel) !== \"private\") continue;\n this.#pendingTeardowns.delete(channel);\n this.#teardownSubscription(shared);\n }\n\n try {\n privateClient?.disconnect();\n } catch {\n // noop\n }\n }\n\n /**\n * Subscribes to a realtime channel and returns an unsubscribe function. Missing\n * authentication is reported to `onError`, or thrown synchronously when no error\n * observer is provided. Non-retryable token failures stop automatic retries;\n * calling subscribe again after correcting the failure restarts private realtime.\n */\n subscribe<T>(channel: string, handlers: SubscribeHandlers<T>): () => void {\n let shared: SharedSubscription;\n try {\n shared = this.#getOrCreateSubscription(channel);\n } catch (error) {\n if (!(error instanceof AuthenticationError)) throw error;\n if (!handlers.onError) throw error;\n\n const ctx = createSdkSubscriptionErrorContext(channel, \"auth\", error);\n queueMicrotask(() => this.#callErrorHandler(handlers.onError, ctx));\n return () => {};\n }\n shared.consumers++;\n\n const publicationHandler = handlers.onPublication;\n const errorHandler = handlers.onError;\n const subscribedHandler = handlers.onSubscribed;\n const unsubscribedHandler = handlers.onUnsubscribed;\n\n const onError: ErrorHandler | undefined = errorHandler\n ? (ctx) => this.#callErrorHandler(errorHandler, ctx)\n : undefined;\n const onPub: PublicationHandler = (data) => {\n this.#callConsumerHandler(\n channel,\n \"publication_handler\",\n () => publicationHandler(data as T),\n onError,\n );\n };\n let lastSubscribedEpoch = -1;\n const onSubscribed = subscribedHandler\n ? (subscriptionEpoch: number) => {\n if (subscriptionEpoch <= lastSubscribedEpoch) return;\n lastSubscribedEpoch = subscriptionEpoch;\n this.#callConsumerHandler(\n channel,\n \"subscribed_handler\",\n subscribedHandler,\n onError,\n );\n }\n : undefined;\n const onUnsubscribed = unsubscribedHandler\n ? () =>\n this.#callConsumerHandler(\n channel,\n \"unsubscribed_handler\",\n unsubscribedHandler,\n onError,\n )\n : undefined;\n\n shared.publicationHandlers.add(onPub);\n\n if (onSubscribed) shared.subscribedHandlers.add(onSubscribed);\n if (onUnsubscribed) shared.unsubscribedHandlers.add(onUnsubscribed);\n if (onError) shared.errorHandlers.add(onError);\n\n // Only an explicit subscribe restarts terminal private token failures.\n if (this.#channelKind(channel) === \"private\") {\n const reconnect = shared.client?.state === \"disconnected\";\n const resubscribe = shared.sub?.state === \"unsubscribed\";\n // hasAuth() reads the token provider, so only call it when a restart is possible.\n if ((reconnect || resubscribe) && this.#hasAuth()) {\n if (reconnect) shared.client?.connect();\n if (resubscribe) shared.sub?.subscribe();\n }\n }\n\n let closed = false;\n if (onSubscribed && shared.sub?.state === \"subscribed\") {\n const subscriptionEpoch = shared.subscriptionEpoch;\n queueMicrotask(() => {\n if (closed || shared.sub?.state !== \"subscribed\") return;\n onSubscribed(subscriptionEpoch);\n });\n }\n\n return () => {\n if (closed) return;\n closed = true;\n\n shared.publicationHandlers.delete(onPub);\n if (onSubscribed) shared.subscribedHandlers.delete(onSubscribed);\n if (onUnsubscribed) shared.unsubscribedHandlers.delete(onUnsubscribed);\n if (onError) shared.errorHandlers.delete(onError);\n\n shared.consumers--;\n if (shared.consumers <= 0) {\n const currentShared = this.#sharedSubs.get(channel);\n if (currentShared !== shared) return;\n\n this.#sharedSubs.delete(channel);\n this.#pendingTeardowns.set(channel, shared);\n\n queueMicrotask(() => {\n if (this.#pendingTeardowns.get(channel) !== shared) return;\n this.#pendingTeardowns.delete(channel);\n\n this.#teardownSubscription(shared);\n\n if (this.#sharedSubs.size === 0 && this.#pendingTeardowns.size === 0) {\n this.#disconnect();\n }\n });\n }\n };\n }\n\n /**\n * Connects to a realtime channel with a custom message decoder.\n */\n connectChannel<T extends DescMessage>(params: ConnectChannelParams<T>): () => void {\n return this.subscribe<Uint8Array>(params.channel, {\n onPublication: (data) => {\n let decoded: MessageShape<T>;\n try {\n decoded = fromBinary(params.schema, data);\n } catch (error) {\n this.#callErrorHandler(\n params.onError,\n createSdkSubscriptionErrorContext(params.channel, \"decode\", error),\n );\n return;\n }\n params.onPublication(decoded);\n },\n onSubscribed: params.onConnected,\n onUnsubscribed: params.onDisconnected,\n onError: params.onError,\n });\n }\n\n /**\n * Connects to a realtime channel that emits protobuf messages.\n */\n connectProtoChannel<T extends DescMessage>(params: ConnectChannelParams<T>): () => void {\n return this.subscribe<Uint8Array | MessageShape<T>>(params.channel, {\n onPublication: (data) => {\n let msg: MessageShape<T> | null;\n try {\n msg = decodeProtoFrame(params.schema, data);\n } catch (error) {\n this.#callErrorHandler(\n params.onError,\n createSdkSubscriptionErrorContext(params.channel, \"decode\", error),\n );\n return;\n }\n if (!msg) {\n this.#callErrorHandler(\n params.onError,\n createSdkSubscriptionErrorContext(\n params.channel,\n \"decode\",\n \"Unable to decode protobuf frame\",\n ),\n );\n return;\n }\n params.onPublication(msg);\n },\n onSubscribed: params.onConnected,\n onUnsubscribed: params.onDisconnected,\n onError: params.onError,\n });\n }\n\n /**\n * Disconnects the realtime client from all active channels.\n */\n disconnect(): void {\n this.#disconnect();\n }\n\n /**\n * Disconnects authenticated realtime state without touching public channels.\n */\n disconnectPrivate(): void {\n this.#disconnectPrivate();\n }\n\n get isConnected(): boolean {\n return this.#publicClient !== null || this.#privateClient !== null;\n }\n\n get activeChannels(): number {\n return this.#sharedSubs.size;\n }\n\n get totalConsumers(): number {\n let total = 0;\n for (const shared of this.#sharedSubs.values()) {\n total += shared.consumers;\n }\n return total;\n }\n}\n"],"mappings":"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"}
@@ -70,7 +70,7 @@ var AccountSignerAuthService = class extends AuthService {
70
70
  const uri = resolveChallengeUri(options.uri ?? this.#challengeUri);
71
71
  const { message } = await this.createWalletChallenge({
72
72
  smartAccountAddress,
73
- signerAddress: accountSigner.accountAddress,
73
+ signerAddress: ownerAddress,
74
74
  uri,
75
75
  purpose: "login"
76
76
  });