{"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts","../src/rpc-subscriptions-channel.ts","../../event-target-impl/src/index.browser.ts","../src/rpc-subscriptions-pubsub-plan.ts"],"names":["SolanaError","SOLANA_ERROR__RPC_SUBSCRIPTIONS__CANNOT_CREATE_SUBSCRIPTION_PLAN","createAsyncIterableFromDataPublisher","AbortController","demultiplexDataPublisher","createRpcMessage","getSolanaErrorFromJsonRpcError","safeRace","SOLANA_ERROR__RPC_SUBSCRIPTIONS__EXPECTED_SERVER_SUBSCRIPTION_ID","SOLANA_ERROR__INVARIANT_VIOLATION__DATA_PUBLISHER_CHANNEL_UNIMPLEMENTED"],"mappings":"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","file":"index.browser.cjs","sourcesContent":["import { SOLANA_ERROR__RPC_SUBSCRIPTIONS__CANNOT_CREATE_SUBSCRIPTION_PLAN, SolanaError } from '@solana/errors';\nimport { Callable, Flatten, OverloadImplementations, UnionToIntersection } from '@solana/rpc-spec-types';\nimport { createAsyncIterableFromDataPublisher } from '@solana/subscribable';\n\nimport { RpcSubscriptionsApi, RpcSubscriptionsPlan } from './rpc-subscriptions-api';\nimport { PendingRpcSubscriptionsRequest, RpcSubscribeOptions } from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig = Readonly<{\n api: RpcSubscriptionsApi;\n transport: RpcSubscriptionsTransport;\n}>;\n\n/**\n * An object that exposes all of the functions described by `TRpcSubscriptionsMethods`.\n *\n * Calling each method returns a\n * {@link PendingRpcSubscriptionsRequest | PendingRpcSubscriptionsRequest} where\n * `TNotification` is that method's notification type.\n */\nexport type RpcSubscriptions = {\n [TMethodName in keyof TRpcSubscriptionsMethods]: PendingRpcSubscriptionsRequestBuilder<\n OverloadImplementations\n >;\n};\n\ntype PendingRpcSubscriptionsRequestBuilder = UnionToIntersection<\n Flatten<{\n [P in keyof TSubscriptionMethodImplementations]: PendingRpcSubscriptionsRequestReturnTypeMapper<\n TSubscriptionMethodImplementations[P]\n >;\n }>\n>;\n\ntype PendingRpcSubscriptionsRequestReturnTypeMapper =\n // Check that this property of the TRpcSubscriptionMethods interface is, in fact, a function.\n TSubscriptionMethodImplementation extends Callable\n ? (\n ...args: Parameters\n ) => PendingRpcSubscriptionsRequest>\n : never;\n\n/**\n * Creates a {@link RpcSubscriptions} instance given a\n * {@link RpcSubscriptionsApi | RpcSubscriptionsApi} and a\n * {@link RpcSubscriptionsTransport} capable of fulfilling them.\n */\nexport function createSubscriptionRpc(\n rpcConfig: RpcSubscriptionsConfig,\n): RpcSubscriptions {\n return new Proxy(rpcConfig.api, {\n defineProperty() {\n return false;\n },\n deleteProperty() {\n return false;\n },\n get(target, p, receiver) {\n if (p === 'then') {\n return undefined;\n }\n return function (...rawParams: unknown[]) {\n const notificationName = p.toString();\n const createRpcSubscriptionPlan = Reflect.get(target, notificationName, receiver);\n if (!createRpcSubscriptionPlan) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS__CANNOT_CREATE_SUBSCRIPTION_PLAN, {\n notificationName,\n });\n }\n const subscriptionPlan = createRpcSubscriptionPlan(...rawParams);\n return createPendingRpcSubscription(rpcConfig.transport, subscriptionPlan);\n };\n },\n }) as RpcSubscriptions;\n}\n\nfunction createPendingRpcSubscription(\n transport: RpcSubscriptionsTransport,\n subscriptionsPlan: RpcSubscriptionsPlan,\n): PendingRpcSubscriptionsRequest {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise> {\n const notificationsDataPublisher = await transport({\n signal: abortSignal,\n ...subscriptionsPlan,\n });\n return createAsyncIterableFromDataPublisher({\n abortSignal,\n dataChannelName: 'notification',\n dataPublisher: notificationsDataPublisher,\n errorChannelName: 'error',\n });\n },\n };\n}\n","import { Callable, RpcRequest, RpcRequestTransformer } from '@solana/rpc-spec-types';\nimport { DataPublisher } from '@solana/subscribable';\n\nimport { RpcSubscriptionsChannel } from './rpc-subscriptions-channel';\nimport { RpcSubscriptionsTransportDataEvents } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n planExecutor: RpcSubscriptionsPlanExecutor>;\n /**\n * An optional function that transforms the {@link RpcRequest} before it is sent to the JSON RPC\n * server.\n *\n * This is useful when the params supplied by the caller need to be transformed before\n * forwarding the message to the server. Use cases for this include applying defaults,\n * forwarding calls to renamed methods, and serializing complex values.\n */\n requestTransformer?: RpcRequestTransformer;\n}>;\n\n/**\n * A function that implements a protocol for subscribing and unsubscribing from notifications given\n * a {@link RpcSubscriptionsChannel}, a {@link RpcRequest}, and an `AbortSignal`.\n *\n * @returns A {@link DataPublisher} that emits {@link RpcSubscriptionsTransportDataEvents}\n */\ntype RpcSubscriptionsPlanExecutor = (\n config: Readonly<{\n channel: RpcSubscriptionsChannel;\n request: RpcRequest;\n signal: AbortSignal;\n }>,\n) => Promise>>;\n\n/**\n * This type allows an {@link RpcSubscriptionsApi} to describe how a particular subscription should\n * be issued to the JSON RPC server.\n *\n * Given a function that was called on a {@link RpcSubscriptions}, this object exposes an `execute`\n * function that dictates which subscription request will be sent, how the underlying transport will\n * be used, and how the notifications will be transformed.\n *\n * This function accepts a {@link RpcSubscriptionsChannel} and an `AbortSignal` and asynchronously\n * returns a {@link DataPublisher}. This gives us the opportunity to:\n *\n * - define the `payload` from the requested method name and parameters before passing it to the\n * channel.\n * - call the underlying channel zero, one or multiple times depending on the use-case (e.g.\n * caching or coalescing multiple subscriptions).\n * - transform the notification from the JSON RPC server, in case it does not match the\n * `TNotification` specified by the\n * {@link PendingRpcSubscriptionsRequest | PendingRpcSubscriptionsRequest} emitted\n * from the publisher returned.\n */\nexport type RpcSubscriptionsPlan = Readonly<{\n /**\n * This method may be called with a newly-opened channel or a pre-established channel.\n */\n execute: (\n config: Readonly<{\n channel: RpcSubscriptionsChannel;\n signal: AbortSignal;\n }>,\n ) => Promise>>;\n /**\n * This request is used to uniquely identify the subscription.\n * It typically comes from the method name and parameters of the subscription call,\n * after potentially being transformed by the RPC Subscriptions API.\n */\n request: RpcRequest;\n}>;\n\n/**\n * For each of `TRpcSubscriptionsMethods`, this object exposes a method with the same name that maps\n * between its input arguments and a\n * {@link RpcSubscriptionsPlan | RpcSubscriptionsPlan} that implements the execution\n * of a JSON RPC subscription for `TNotifications`.\n */\nexport type RpcSubscriptionsApi = {\n [MethodName in keyof TRpcSubscriptionMethods]: RpcSubscriptionsReturnTypeMapper<\n TRpcSubscriptionMethods[MethodName]\n >;\n};\n\ntype RpcSubscriptionsReturnTypeMapper = TRpcMethod extends Callable\n ? (...rawParams: unknown[]) => RpcSubscriptionsPlan>\n : never;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype RpcSubscriptionsApiMethod = (...args: any) => any;\nexport interface RpcSubscriptionsApiMethods {\n [methodName: string]: RpcSubscriptionsApiMethod;\n}\n\n/**\n * Creates a JavaScript proxy that converts _any_ function call called on it to a\n * {@link RpcSubscriptionsPlan} by creating an `execute` function that:\n *\n * - calls the supplied {@link RpcSubscriptionsApiConfig.planExecutor} with a JSON RPC v2 payload\n * object with the requested `methodName` and `params` properties, optionally transformed by\n * {@link RpcSubscriptionsApiConfig.requestTransformer}.\n *\n * @example\n * ```ts\n * // For example, given this `RpcSubscriptionsApi`:\n * const rpcSubscriptionsApi = createJsonRpcSubscriptionsApi({\n * async planExecutor({ channel, request }) {\n * await channel.send(request);\n * return {\n * ...channel,\n * on(type, listener, options) {\n * if (type !== 'message') {\n * return channel.on(type, listener, options);\n * }\n * return channel.on(\n * 'message',\n * function resultGettingListener(message) {\n * listener(message.result);\n * },\n * options,\n * );\n * }\n * }\n * },\n * requestTransformer: (...rawParams) => rawParams.reverse(),\n * });\n *\n * // ...the following function call:\n * rpcSubscriptionsApi.foo('bar', { baz: 'bat' });\n *\n * // ...will produce a `RpcSubscriptionsPlan` that:\n * // - Uses the following payload: { id: 1, jsonrpc: '2.0', method: 'foo', params: [{ baz: 'bat' }, 'bar'] }.\n * // - Emits the \"result\" property of each RPC Subscriptions message.\n * ```\n */\nexport function createRpcSubscriptionsApi(\n config: RpcSubscriptionsApiConfig,\n): RpcSubscriptionsApi {\n return new Proxy({} as RpcSubscriptionsApi, {\n defineProperty() {\n return false;\n },\n deleteProperty() {\n return false;\n },\n get>(\n ...args: Parameters>['get']>>\n ) {\n const [_, p] = args;\n const methodName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...params: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsPlan> {\n const rawRequest = { methodName, params };\n const request = config.requestTransformer ? config.requestTransformer(rawRequest) : rawRequest;\n return {\n execute(planConfig) {\n return config.planExecutor({ ...planConfig, request });\n },\n request,\n };\n };\n },\n });\n}\n","import {\n SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CLOSED_BEFORE_MESSAGE_BUFFERED,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CONNECTION_CLOSED,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_FAILED_TO_CONNECT,\n SolanaError,\n} from '@solana/errors';\nimport { DataPublisher } from '@solana/subscribable';\n\ntype RpcSubscriptionsChannelSolanaErrorCode =\n | typeof SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CLOSED_BEFORE_MESSAGE_BUFFERED\n | typeof SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CONNECTION_CLOSED\n | typeof SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_FAILED_TO_CONNECT;\n\nexport type RpcSubscriptionChannelEvents = {\n /**\n * Fires when the channel closes unexpectedly.\n * @eventProperty\n */\n error: SolanaError;\n /**\n * Fires on every message received from the remote end.\n * @eventProperty\n */\n message: TInboundMessage;\n};\n\n/**\n * A {@link DataPublisher} on which you can subscribe to events of type\n * {@link RpcSubscriptionChannelEvents | RpcSubscriptionChannelEvents}.\n * Additionally, you can use this object to send messages of type `TOutboundMessage` back to the\n * remote end by calling its {@link RpcSubscriptionsChannel.send | `send(message)`} method.\n */\nexport interface RpcSubscriptionsChannel extends DataPublisher<\n RpcSubscriptionChannelEvents\n> {\n send(message: TOutboundMessage): Promise;\n}\n\n/**\n * A channel creator is a function that accepts an `AbortSignal`, returns a new\n * {@link RpcSubscriptionsChannel}, and tears down the channel when the abort signal fires.\n */\nexport type RpcSubscriptionsChannelCreator = (\n config: Readonly<{\n abortSignal: AbortSignal;\n }>,\n) => Promise>;\n\n/**\n * Given a channel with inbound messages of type `T` and a function of type `T => U`, returns a new\n * channel with inbound messages of type `U`.\n *\n * Note that this only affects messages of type `\"message\"` and thus, does not affect incoming error\n * messages.\n *\n * @example Parsing incoming JSON messages\n * ```ts\n * const transformedChannel = transformChannelInboundMessages(channel, JSON.parse);\n * ```\n */\nexport function transformChannelInboundMessages(\n channel: RpcSubscriptionsChannel,\n transform: (message: TInboundMessage) => TNewInboundMessage,\n): RpcSubscriptionsChannel {\n return Object.freeze>({\n ...channel,\n on(type, subscriber, options) {\n if (type !== 'message') {\n return channel.on(\n type,\n subscriber as (data: RpcSubscriptionChannelEvents[typeof type]) => void,\n options,\n );\n }\n return channel.on(\n 'message',\n message => (subscriber as (data: TNewInboundMessage) => void)(transform(message)),\n options,\n );\n },\n });\n}\n\n/**\n * Given a channel with outbound messages of type `T` and a function of type `U => T`, returns a new\n * channel with outbound messages of type `U`.\n *\n * @example Stringifying JSON messages before sending them over the wire\n * ```ts\n * const transformedChannel = transformChannelOutboundMessages(channel, JSON.stringify);\n * ```\n */\nexport function transformChannelOutboundMessages(\n channel: RpcSubscriptionsChannel,\n transform: (message: TNewOutboundMessage) => TOutboundMessage,\n): RpcSubscriptionsChannel {\n return Object.freeze>({\n ...channel,\n send: message => channel.send(transform(message)),\n });\n}\n","export const AbortController = globalThis.AbortController;\nexport const EventTarget = globalThis.EventTarget;\n","import {\n getSolanaErrorFromJsonRpcError,\n SOLANA_ERROR__INVARIANT_VIOLATION__DATA_PUBLISHER_CHANNEL_UNIMPLEMENTED,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS__EXPECTED_SERVER_SUBSCRIPTION_ID,\n SolanaError,\n} from '@solana/errors';\nimport { AbortController } from '@solana/event-target-impl';\nimport { safeRace } from '@solana/promises';\nimport { createRpcMessage, RpcRequest, RpcResponseData, RpcResponseTransformer } from '@solana/rpc-spec-types';\nimport { DataPublisher } from '@solana/subscribable';\nimport { demultiplexDataPublisher } from '@solana/subscribable';\n\nimport { RpcSubscriptionChannelEvents } from './rpc-subscriptions-channel';\nimport { RpcSubscriptionsChannel } from './rpc-subscriptions-channel';\n\ntype Config = Readonly<{\n channel: RpcSubscriptionsChannel | RpcResponseData>;\n responseTransformer?: RpcResponseTransformer;\n signal: AbortSignal;\n subscribeRequest: RpcRequest;\n unsubscribeMethodName: string;\n}>;\n\ntype RpcNotification = Readonly<{\n method: string;\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\ntype RpcSubscriptionNotificationEvents = Omit, 'message'> & {\n notification: TNotification;\n};\n\nconst subscriberCountBySubscriptionIdByChannel = new WeakMap>();\nfunction decrementSubscriberCountAndReturnNewCount(channel: WeakKey, subscriptionId?: number): number | undefined {\n return augmentSubscriberCountAndReturnNewCount(-1, channel, subscriptionId);\n}\nfunction incrementSubscriberCount(channel: WeakKey, subscriptionId?: number): void {\n augmentSubscriberCountAndReturnNewCount(1, channel, subscriptionId);\n}\nfunction getSubscriberCountBySubscriptionIdForChannel(channel: WeakKey): Record {\n let subscriberCountBySubscriptionId = subscriberCountBySubscriptionIdByChannel.get(channel);\n if (!subscriberCountBySubscriptionId) {\n subscriberCountBySubscriptionIdByChannel.set(channel, (subscriberCountBySubscriptionId = {}));\n }\n return subscriberCountBySubscriptionId;\n}\nfunction augmentSubscriberCountAndReturnNewCount(\n amount: -1 | 1,\n channel: WeakKey,\n subscriptionId?: number,\n): number | undefined {\n if (subscriptionId === undefined) {\n return;\n }\n const subscriberCountBySubscriptionId = getSubscriberCountBySubscriptionIdForChannel(channel);\n if (!subscriberCountBySubscriptionId[subscriptionId] && amount > 0) {\n subscriberCountBySubscriptionId[subscriptionId] = 0;\n }\n const newCount = amount + subscriberCountBySubscriptionId[subscriptionId];\n if (newCount <= 0) {\n delete subscriberCountBySubscriptionId[subscriptionId];\n } else {\n subscriberCountBySubscriptionId[subscriptionId] = newCount;\n }\n return newCount;\n}\n\nconst cache = new WeakMap();\nfunction getMemoizedDemultiplexedNotificationPublisherFromChannelAndResponseTransformer(\n channel: RpcSubscriptionsChannel>,\n subscribeRequest: RpcRequest,\n responseTransformer?: RpcResponseTransformer,\n): DataPublisher<{\n [channelName: `notification:${number}`]: TNotification;\n}> {\n let publisherByResponseTransformer = cache.get(channel);\n if (!publisherByResponseTransformer) {\n cache.set(channel, (publisherByResponseTransformer = new WeakMap()));\n }\n const responseTransformerKey = responseTransformer ?? channel;\n let publisher = publisherByResponseTransformer.get(responseTransformerKey);\n if (!publisher) {\n publisherByResponseTransformer.set(\n responseTransformerKey,\n (publisher = demultiplexDataPublisher(channel, 'message', rawMessage => {\n const message = rawMessage as RpcNotification | RpcResponseData;\n if (!('method' in message)) {\n return;\n }\n const transformedNotification = responseTransformer\n ? responseTransformer(message.params.result, subscribeRequest)\n : message.params.result;\n return [`notification:${message.params.subscription}`, transformedNotification];\n })),\n );\n }\n return publisher;\n}\n\n/**\n * Given a channel, this function executes the particular subscription plan required by the Solana\n * JSON RPC Subscriptions API.\n *\n * @param config\n *\n * 1. Calls the `subscribeRequest` on the remote RPC\n * 2. Waits for a response containing the subscription id\n * 3. Returns a {@link DataPublisher} that publishes notifications related to that subscriptions id,\n * filtering out all others\n * 4. Calls the `unsubscribeMethodName` on the remote RPC when the abort signal is fired.\n */\nexport async function executeRpcPubSubSubscriptionPlan({\n channel,\n responseTransformer,\n signal,\n subscribeRequest,\n unsubscribeMethodName,\n}: Config): Promise>> {\n let subscriptionId: number | undefined;\n channel.on(\n 'error',\n () => {\n // An error on the channel indicates that the subscriptions are dead.\n // There is no longer any sense hanging on to subscription ids.\n // Erasing it here will prevent the unsubscribe code from running.\n subscriptionId = undefined;\n subscriberCountBySubscriptionIdByChannel.delete(channel);\n },\n { signal },\n );\n /**\n * STEP 1\n * Create a promise that rejects if this subscription is aborted and sends\n * the unsubscribe message if the subscription is active at that time.\n */\n const abortPromise = new Promise((_, reject) => {\n function handleAbort(this: AbortSignal) {\n /**\n * Because of https://github.com/solana-labs/solana/pull/18943, two subscriptions for\n * materially the same notification will be coalesced on the server. This means they\n * will be assigned the same subscription id, and will occupy one subscription slot. We\n * must be careful not to send the unsubscribe message until the last subscriber aborts.\n */\n if (decrementSubscriberCountAndReturnNewCount(channel, subscriptionId) === 0) {\n const unsubscribePayload = createRpcMessage({\n methodName: unsubscribeMethodName,\n params: [subscriptionId],\n });\n subscriptionId = undefined;\n channel.send(unsubscribePayload).catch(() => {});\n }\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n reject(this.reason);\n }\n if (signal.aborted) {\n handleAbort.call(signal);\n } else {\n signal.addEventListener('abort', handleAbort);\n }\n });\n /**\n * STEP 2\n * Send the subscription request.\n */\n const subscribePayload = createRpcMessage(subscribeRequest);\n await channel.send(subscribePayload);\n /**\n * STEP 3\n * Wait for the acknowledgement from the server with the subscription id.\n */\n const subscriptionIdPromise = new Promise((resolve, reject) => {\n const abortController = new AbortController();\n signal.addEventListener('abort', abortController.abort.bind(abortController));\n const options = { signal: abortController.signal } as const;\n channel.on(\n 'error',\n err => {\n abortController.abort();\n reject(err);\n },\n options,\n );\n channel.on(\n 'message',\n message => {\n if (message && typeof message === 'object' && 'id' in message && message.id === subscribePayload.id) {\n abortController.abort();\n if ('error' in message) {\n reject(getSolanaErrorFromJsonRpcError(message.error));\n } else {\n resolve(message.result);\n }\n }\n },\n options,\n );\n });\n subscriptionId = await safeRace([abortPromise, subscriptionIdPromise]);\n if (subscriptionId == null) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS__EXPECTED_SERVER_SUBSCRIPTION_ID);\n }\n incrementSubscriberCount(channel, subscriptionId);\n /**\n * STEP 4\n * Filter out notifications unrelated to this subscription.\n */\n const notificationPublisher = getMemoizedDemultiplexedNotificationPublisherFromChannelAndResponseTransformer(\n channel,\n subscribeRequest,\n responseTransformer,\n );\n const notificationKey = `notification:${subscriptionId}` as const;\n return {\n on(type, listener, options) {\n switch (type) {\n case 'notification':\n return notificationPublisher.on(\n notificationKey,\n listener as (data: RpcSubscriptionNotificationEvents['notification']) => void,\n options,\n );\n case 'error':\n return channel.on(\n 'error',\n listener as (data: RpcSubscriptionNotificationEvents['error']) => void,\n options,\n );\n default:\n throw new SolanaError(SOLANA_ERROR__INVARIANT_VIOLATION__DATA_PUBLISHER_CHANNEL_UNIMPLEMENTED, {\n channelName: type,\n supportedChannelNames: ['notification', 'error'],\n });\n }\n },\n };\n}\n"]}