@polyester/sdk 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +18 -12
- package/dist/account-signer/create-polyester-account-signer.d.ts +9 -5
- package/dist/account-signer/create-polyester-account-signer.d.ts.map +1 -1
- package/dist/account-signer/create-polyester-account-signer.js +9 -5
- package/dist/account-signer/create-polyester-account-signer.js.map +1 -1
- package/dist/account-signer/types.d.ts +10 -4
- package/dist/account-signer/types.d.ts.map +1 -1
- package/dist/account-signer/types.js.map +1 -1
- package/dist/core-client.d.ts +3 -0
- package/dist/core-client.d.ts.map +1 -1
- package/dist/core-client.js +23 -45
- package/dist/core-client.js.map +1 -1
- package/dist/gen/auth/v1/auth_pb.d.ts +7 -4
- package/dist/gen/auth/v1/auth_pb.d.ts.map +1 -1
- package/dist/gen/auth/v1/auth_pb.js.map +1 -1
- package/dist/gen/claims/v1/claims_pb.d.ts +313 -0
- package/dist/gen/claims/v1/claims_pb.d.ts.map +1 -0
- package/dist/gen/claims/v1/claims_pb.js +135 -0
- package/dist/gen/claims/v1/claims_pb.js.map +1 -0
- package/dist/gen/index.d.ts +2 -1
- package/dist/gen/index.js +2 -1
- package/dist/gen/orders/v1/orders_pb.d.ts +50 -3
- package/dist/gen/orders/v1/orders_pb.d.ts.map +1 -1
- package/dist/gen/orders/v1/orders_pb.js +55 -43
- package/dist/gen/orders/v1/orders_pb.js.map +1 -1
- package/dist/gen/orders/v1/orders_read_pb.d.ts +10 -0
- package/dist/gen/orders/v1/orders_read_pb.d.ts.map +1 -1
- package/dist/gen/orders/v1/orders_read_pb.js +3 -1
- package/dist/gen/orders/v1/orders_read_pb.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/realtime/client.js +45 -26
- package/dist/realtime/client.js.map +1 -1
- package/dist/services/accounts/accounts.schemas.d.ts +2 -2
- package/dist/services/accounts/accounts.schemas.d.ts.map +1 -1
- package/dist/services/accounts/accounts.schemas.js +3 -3
- package/dist/services/accounts/accounts.schemas.js.map +1 -1
- package/dist/services/address-book/address-book.schemas.d.ts +67 -68
- package/dist/services/address-book/address-book.schemas.d.ts.map +1 -1
- package/dist/services/address-book/address-book.schemas.js +11 -13
- package/dist/services/address-book/address-book.schemas.js.map +1 -1
- package/dist/services/api-keys/api-keys.schemas.d.ts +1 -2
- package/dist/services/api-keys/api-keys.schemas.d.ts.map +1 -1
- package/dist/services/api-keys/api-keys.schemas.js +4 -9
- package/dist/services/api-keys/api-keys.schemas.js.map +1 -1
- package/dist/services/auth/account-signer-auth.js +1 -1
- package/dist/services/auth/account-signer-auth.js.map +1 -1
- package/dist/services/auth/auth.d.ts +2 -3
- package/dist/services/auth/auth.d.ts.map +1 -1
- package/dist/services/auth/auth.js +4 -2
- package/dist/services/auth/auth.js.map +1 -1
- package/dist/services/balances/balances.schemas.d.ts +3 -3
- package/dist/services/balances/balances.schemas.d.ts.map +1 -1
- package/dist/services/balances/balances.schemas.js +7 -12
- package/dist/services/balances/balances.schemas.js.map +1 -1
- package/dist/services/candles/candles.schemas.d.ts +3 -3
- package/dist/services/candles/candles.schemas.d.ts.map +1 -1
- package/dist/services/candles/candles.schemas.js +5 -6
- package/dist/services/candles/candles.schemas.js.map +1 -1
- package/dist/services/chain-analytics/chain-analytics.schemas.d.ts +3 -3
- package/dist/services/chain-analytics/chain-analytics.schemas.d.ts.map +1 -1
- package/dist/services/chain-analytics/chain-analytics.schemas.js +2 -3
- package/dist/services/chain-analytics/chain-analytics.schemas.js.map +1 -1
- package/dist/services/claims/claims.codecs.d.ts +8 -0
- package/dist/services/claims/claims.codecs.d.ts.map +1 -0
- package/dist/services/claims/claims.codecs.js +17 -0
- package/dist/services/claims/claims.codecs.js.map +1 -0
- package/dist/services/claims/claims.d.ts +19 -0
- package/dist/services/claims/claims.d.ts.map +1 -0
- package/dist/services/claims/claims.js +30 -0
- package/dist/services/claims/claims.js.map +1 -0
- package/dist/services/claims/claims.schemas.d.ts +122 -0
- package/dist/services/claims/claims.schemas.d.ts.map +1 -0
- package/dist/services/claims/claims.schemas.js +47 -0
- package/dist/services/claims/claims.schemas.js.map +1 -0
- package/dist/services/claims/claims.types.d.ts +3 -0
- package/dist/services/claims/index.d.ts +5 -0
- package/dist/services/heatmap/heatmap.schemas.d.ts +4 -4
- package/dist/services/heatmap/heatmap.schemas.d.ts.map +1 -1
- package/dist/services/heatmap/heatmap.schemas.js +10 -10
- package/dist/services/heatmap/heatmap.schemas.js.map +1 -1
- package/dist/services/internal-transfers/internal-transfers.schemas.d.ts.map +1 -1
- package/dist/services/internal-transfers/internal-transfers.schemas.js +1 -5
- package/dist/services/internal-transfers/internal-transfers.schemas.js.map +1 -1
- package/dist/services/lifecycle/lifecycle.schemas.d.ts +90 -90
- package/dist/services/lifecycle/lifecycle.schemas.d.ts.map +1 -1
- package/dist/services/lifecycle/lifecycle.schemas.js +10 -11
- package/dist/services/lifecycle/lifecycle.schemas.js.map +1 -1
- package/dist/services/market-overview/market-overview.schemas.d.ts +1 -1
- package/dist/services/market-overview/market-overview.schemas.d.ts.map +1 -1
- package/dist/services/market-overview/market-overview.schemas.js +3 -3
- package/dist/services/market-overview/market-overview.schemas.js.map +1 -1
- package/dist/services/mfa/mfa.schemas.d.ts +11 -11
- package/dist/services/mfa/mfa.schemas.d.ts.map +1 -1
- package/dist/services/mfa/mfa.schemas.js +4 -5
- package/dist/services/mfa/mfa.schemas.js.map +1 -1
- package/dist/services/orderbook/orderbook.schemas.d.ts +1 -1
- package/dist/services/orders/order-enums.codecs.js +2 -1
- package/dist/services/orders/order-enums.codecs.js.map +1 -1
- package/dist/services/orders/order-errors.schemas.d.ts +4 -5
- package/dist/services/orders/order-errors.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-batch.schemas.d.ts +110 -32
- package/dist/services/orders/orders-batch.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-batch.schemas.js +9 -10
- package/dist/services/orders/orders-batch.schemas.js.map +1 -1
- package/dist/services/orders/orders-input.schemas.d.ts +111 -8
- package/dist/services/orders/orders-input.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-input.schemas.js +20 -4
- package/dist/services/orders/orders-input.schemas.js.map +1 -1
- package/dist/services/orders/orders-modify.schemas.d.ts +2 -2
- package/dist/services/orders/orders-modify.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-modify.schemas.js +3 -3
- package/dist/services/orders/orders-modify.schemas.js.map +1 -1
- package/dist/services/orders/orders-output.schemas.d.ts +48 -32
- package/dist/services/orders/orders-output.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-output.schemas.js +16 -16
- package/dist/services/orders/orders-output.schemas.js.map +1 -1
- package/dist/services/orders/orders-risk.schemas.d.ts +0 -1
- package/dist/services/orders/orders-risk.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-risk.schemas.js +4 -4
- package/dist/services/orders/orders-risk.schemas.js.map +1 -1
- package/dist/services/policies/api-key-policies/api-key-policies.schemas.d.ts +4 -4
- package/dist/services/policies/shared.codecs.js +3 -3
- package/dist/services/policies/shared.codecs.js.map +1 -1
- package/dist/services/policies/shared.d.ts +0 -1
- package/dist/services/policies/shared.d.ts.map +1 -1
- package/dist/services/policies/shared.js +2 -3
- package/dist/services/policies/shared.js.map +1 -1
- package/dist/services/policies/subaccount-policies/subaccount-policies.schemas.d.ts +2 -2
- package/dist/services/policies/subaccount-policies/subaccount-policies.schemas.d.ts.map +1 -1
- package/dist/services/policies/subaccount-policies/subaccount-policies.schemas.js +2 -5
- package/dist/services/policies/subaccount-policies/subaccount-policies.schemas.js.map +1 -1
- package/dist/services/rate-limits/rate-limits.schemas.d.ts +6 -7
- package/dist/services/rate-limits/rate-limits.schemas.d.ts.map +1 -1
- package/dist/services/rate-limits/rate-limits.schemas.js +2 -3
- package/dist/services/rate-limits/rate-limits.schemas.js.map +1 -1
- package/dist/services/social-verification/social-verification.schemas.d.ts.map +1 -1
- package/dist/services/social-verification/social-verification.schemas.js +4 -4
- package/dist/services/social-verification/social-verification.schemas.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.d.ts +23 -24
- package/dist/services/subaccounts/subaccounts.schemas.d.ts.map +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.js +10 -12
- package/dist/services/subaccounts/subaccounts.schemas.js.map +1 -1
- package/dist/services/trades/trades.schemas.d.ts +1 -1
- package/dist/services/trades/trades.schemas.d.ts.map +1 -1
- package/dist/services/trades/trades.schemas.js +4 -8
- package/dist/services/trades/trades.schemas.js.map +1 -1
- package/dist/services/transfers/transfers.schemas.d.ts +3 -4
- package/dist/services/transfers/transfers.schemas.d.ts.map +1 -1
- package/dist/services/transfers/transfers.schemas.js +5 -10
- package/dist/services/transfers/transfers.schemas.js.map +1 -1
- package/dist/services/triggers/trigger-input.schemas.d.ts +2 -2
- package/dist/services/triggers/triggers-output.schemas.d.ts +56 -58
- package/dist/services/triggers/triggers-output.schemas.d.ts.map +1 -1
- package/dist/services/triggers/triggers-output.schemas.js +34 -36
- package/dist/services/triggers/triggers-output.schemas.js.map +1 -1
- package/dist/services/whiteboard/whiteboard.schemas.d.ts +42 -42
- package/dist/services/whiteboard/whiteboard.schemas.d.ts.map +1 -1
- package/dist/services/whiteboard/whiteboard.schemas.js +9 -10
- package/dist/services/whiteboard/whiteboard.schemas.js.map +1 -1
- package/dist/shared/proto-enum-codec.js +11 -6
- package/dist/shared/proto-enum-codec.js.map +1 -1
- package/dist/shared/rate-limit.schemas.d.ts +4 -5
- package/dist/shared/rate-limit.schemas.d.ts.map +1 -1
- package/dist/shared/rate-limit.schemas.js +41 -46
- package/dist/shared/rate-limit.schemas.js.map +1 -1
- package/dist/shared/schemas.js +5 -1
- package/dist/shared/schemas.js.map +1 -1
- package/dist/shared/transports.d.ts +5 -1
- package/dist/shared/transports.d.ts.map +1 -1
- package/dist/shared/transports.js.map +1 -1
- package/dist/utils/timestamp.js +8 -1
- package/dist/utils/timestamp.js.map +1 -1
- package/dist/wired-services.d.ts.map +1 -1
- package/dist/wired-services.js +2 -0
- package/dist/wired-services.js.map +1 -1
- package/package.json +1 -1
|
@@ -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":"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"}
|
|
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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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResolveHint
|
|
1
|
+
import { ResolveHint } from "../../gen/auth/v1/resolve_pb.js";
|
|
2
2
|
import * as v from "valibot";
|
|
3
3
|
//#region src/services/accounts/accounts.schemas.d.ts
|
|
4
4
|
declare const ResolveAccountInputSchema: v.ObjectSchema<{
|
|
@@ -9,7 +9,7 @@ declare const ResolveAccountInputSchema: v.ObjectSchema<{
|
|
|
9
9
|
type ResolveAccountInput = v.InferInput<typeof ResolveAccountInputSchema>;
|
|
10
10
|
declare const ResolvedAccountSchema: v.ObjectSchema<{
|
|
11
11
|
readonly smartAccountAddress: v.StringSchema<undefined>;
|
|
12
|
-
readonly kind: v.SchemaWithPipe<readonly [v.
|
|
12
|
+
readonly kind: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.TransformAction<number, "unspecified" | "sub" | "root">]>;
|
|
13
13
|
readonly rootUsername: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
14
14
|
readonly subaccountLabel: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
15
15
|
readonly accountId: v.SchemaWithPipe<readonly [v.BigintSchema<undefined>, v.TransformAction<bigint, string>]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts.schemas.d.ts","names":[],"sources":["../../../src/services/accounts/accounts.schemas.ts"],"mappings":";;;cAea,2BAAyB,EAAA;;;;;KAS1B,sBAAsB,EAAE,kBAAkB;cAEzC,uBAAqB,EAAA;;;;;;;
|
|
1
|
+
{"version":3,"file":"accounts.schemas.d.ts","names":[],"sources":["../../../src/services/accounts/accounts.schemas.ts"],"mappings":";;;cAea,2BAAyB,EAAA;;;;;KAS1B,sBAAsB,EAAE,kBAAkB;cAEzC,uBAAqB,EAAA;;;;;;;KAUtB,kBAAkB,EAAE,mBAAmB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { enumLabelSchema } from "../../shared/proto-enum-codec.js";
|
|
2
2
|
import { PublicIdSchema } from "../../shared/schemas.js";
|
|
3
|
-
import
|
|
3
|
+
import "../../gen/auth/v1/resolve_pb.js";
|
|
4
4
|
import { ResolveHintCodec, ResolvedAccountKindCodec } from "./accounts.codecs.js";
|
|
5
5
|
import * as v from "valibot";
|
|
6
6
|
//#region src/services/accounts/accounts.schemas.ts
|
|
@@ -17,7 +17,7 @@ const ResolveAccountInputSchema = v.object({
|
|
|
17
17
|
});
|
|
18
18
|
const ResolvedAccountSchema = v.object({
|
|
19
19
|
smartAccountAddress: v.string(),
|
|
20
|
-
kind:
|
|
20
|
+
kind: enumLabelSchema(ResolvedAccountKindCodec.protoToOutput),
|
|
21
21
|
rootUsername: v.optional(v.string()),
|
|
22
22
|
subaccountLabel: v.optional(v.string()),
|
|
23
23
|
accountId: PublicIdSchema
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts.schemas.js","names":[
|
|
1
|
+
{"version":3,"file":"accounts.schemas.js","names":[],"sources":["../../../src/services/accounts/accounts.schemas.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport * as ProtoResolve from \"../../gen/auth/v1/resolve_pb.js\";\nimport { enumLabelSchema } from \"../../shared/proto-enum-codec.js\";\nimport { PublicIdSchema } from \"../../shared/schemas.js\";\nimport { ResolvedAccountKindCodec, ResolveHintCodec } from \"./accounts.codecs.js\";\n\nfunction normalizeResolveHint(value?: string): ProtoResolve.ResolveHint {\n const raw = (value ?? \"\").trim();\n if (!raw) return ProtoResolve.ResolveHint.RESOLVE_HINT_UNSPECIFIED;\n const key = raw.toUpperCase().replace(/^RESOLVE_HINT_/, \"\");\n return (\n ResolveHintCodec.keyToProtoLookup[key] ?? ProtoResolve.ResolveHint.RESOLVE_HINT_UNSPECIFIED\n );\n}\n\nexport const ResolveAccountInputSchema = v.object({\n query: v.pipe(v.string(), v.trim(), v.minLength(1, \"query is required\")),\n hint: v.pipe(\n v.optional(v.string(), \"\"),\n v.transform((value) => normalizeResolveHint(value)),\n ),\n includeSubaccounts: v.optional(v.boolean(), false),\n});\n\nexport type ResolveAccountInput = v.InferInput<typeof ResolveAccountInputSchema>;\n\nexport const ResolvedAccountSchema = v.object({\n smartAccountAddress: v.string(),\n kind: enumLabelSchema(ResolvedAccountKindCodec.protoToOutput),\n rootUsername: v.optional(v.string()),\n subaccountLabel: v.optional(v.string()),\n accountId: PublicIdSchema,\n});\n\nexport const ResolvedAccountArraySchema = v.optional(v.array(ResolvedAccountSchema), []);\n\nexport type ResolvedAccount = v.InferOutput<typeof ResolvedAccountSchema>;\n"],"mappings":";;;;;;AAMA,SAAS,qBAAqB,OAA0C;CACpE,MAAM,OAAO,SAAS,GAAA,CAAI,KAAK;CAC/B,IAAI,CAAC,KAAK,OAAA;CACV,MAAM,MAAM,IAAI,YAAY,CAAC,CAAC,QAAQ,kBAAkB,EAAE;CAC1D,OACI,iBAAiB,iBAAiB,QAAA;AAE1C;AAEA,MAAa,4BAA4B,EAAE,OAAO;CAC9C,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,KAAK,GAAG,EAAE,UAAU,GAAG,mBAAmB,CAAC;CACvE,MAAM,EAAE,KACJ,EAAE,SAAS,EAAE,OAAO,GAAG,EAAE,GACzB,EAAE,WAAW,UAAU,qBAAqB,KAAK,CAAC,CACtD;CACA,oBAAoB,EAAE,SAAS,EAAE,QAAQ,GAAG,KAAK;AACrD,CAAC;AAID,MAAa,wBAAwB,EAAE,OAAO;CAC1C,qBAAqB,EAAE,OAAO;CAC9B,MAAM,gBAAgB,yBAAyB,aAAa;CAC5D,cAAc,EAAE,SAAS,EAAE,OAAO,CAAC;CACnC,iBAAiB,EAAE,SAAS,EAAE,OAAO,CAAC;CACtC,WAAW;AACf,CAAC;AAED,MAAa,6BAA6B,EAAE,SAAS,EAAE,MAAM,qBAAqB,GAAG,CAAC,CAAC"}
|