UNPKG

@solana/rpc-subscriptions-spec

Version:

A generic implementation of JSON RPC Subscriptions using proxies

1 lines • 33.4 kB
{"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts","../src/rpc-subscriptions-channel.ts","../../event-target-impl/src/index.node.ts","../src/rpc-subscriptions-pubsub-plan.ts"],"names":["SolanaError","SOLANA_ERROR__RPC_SUBSCRIPTIONS__CANNOT_CREATE_SUBSCRIPTION_PLAN","createAsyncIterableFromDataPublisher","AbortController","args","setMaxListeners","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.node.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<TRpcMethods> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\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<TNotification>} where\n * `TNotification` is that method's notification type.\n */\nexport type RpcSubscriptions<TRpcSubscriptionsMethods> = {\n [TMethodName in keyof TRpcSubscriptionsMethods]: PendingRpcSubscriptionsRequestBuilder<\n OverloadImplementations<TRpcSubscriptionsMethods, TMethodName>\n >;\n};\n\ntype PendingRpcSubscriptionsRequestBuilder<TSubscriptionMethodImplementations> = UnionToIntersection<\n Flatten<{\n [P in keyof TSubscriptionMethodImplementations]: PendingRpcSubscriptionsRequestReturnTypeMapper<\n TSubscriptionMethodImplementations[P]\n >;\n }>\n>;\n\ntype PendingRpcSubscriptionsRequestReturnTypeMapper<TSubscriptionMethodImplementation> =\n // Check that this property of the TRpcSubscriptionMethods interface is, in fact, a function.\n TSubscriptionMethodImplementation extends Callable\n ? (\n ...args: Parameters<TSubscriptionMethodImplementation>\n ) => PendingRpcSubscriptionsRequest<ReturnType<TSubscriptionMethodImplementation>>\n : never;\n\n/**\n * Creates a {@link RpcSubscriptions} instance given a\n * {@link RpcSubscriptionsApi | RpcSubscriptionsApi<TRpcSubscriptionsApiMethods>} and a\n * {@link RpcSubscriptionsTransport} capable of fulfilling them.\n */\nexport function createSubscriptionRpc<TRpcSubscriptionsApiMethods>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return new Proxy(rpcConfig.api, {\n defineProperty() {\n return false;\n },\n deleteProperty() {\n return false;\n },\n get(target, p, receiver) {\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<TRpcSubscriptionsApiMethods>;\n}\n\nfunction createPendingRpcSubscription<TNotification>(\n transport: RpcSubscriptionsTransport,\n subscriptionsPlan: RpcSubscriptionsPlan<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n const notificationsDataPublisher = await transport({\n signal: abortSignal,\n ...subscriptionsPlan,\n });\n return createAsyncIterableFromDataPublisher<TNotification>({\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<TApiMethods extends RpcSubscriptionsApiMethods> = Readonly<{\n planExecutor: RpcSubscriptionsPlanExecutor<ReturnType<TApiMethods[keyof TApiMethods]>>;\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<TNotification> = (\n config: Readonly<{\n channel: RpcSubscriptionsChannel<unknown, unknown>;\n request: RpcRequest;\n signal: AbortSignal;\n }>,\n) => Promise<DataPublisher<RpcSubscriptionsTransportDataEvents<TNotification>>>;\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<TNotification>} emitted\n * from the publisher returned.\n */\nexport type RpcSubscriptionsPlan<TNotification> = 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<unknown, unknown>;\n signal: AbortSignal;\n }>,\n ) => Promise<DataPublisher<RpcSubscriptionsTransportDataEvents<TNotification>>>;\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<TNotification>} that implements the execution\n * of a JSON RPC subscription for `TNotifications`.\n */\nexport type RpcSubscriptionsApi<TRpcSubscriptionMethods> = {\n [MethodName in keyof TRpcSubscriptionMethods]: RpcSubscriptionsReturnTypeMapper<\n TRpcSubscriptionMethods[MethodName]\n >;\n};\n\ntype RpcSubscriptionsReturnTypeMapper<TRpcMethod> = TRpcMethod extends Callable\n ? (...rawParams: unknown[]) => RpcSubscriptionsPlan<ReturnType<TRpcMethod>>\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<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config: RpcSubscriptionsApiConfig<TRpcSubscriptionsApiMethods>,\n): RpcSubscriptionsApi<TRpcSubscriptionsApiMethods> {\n return new Proxy({} as RpcSubscriptionsApi<TRpcSubscriptionsApiMethods>, {\n defineProperty() {\n return false;\n },\n deleteProperty() {\n return false;\n },\n get<TNotificationName extends keyof RpcSubscriptionsApi<TRpcSubscriptionsApiMethods>>(\n ...args: Parameters<NonNullable<ProxyHandler<RpcSubscriptionsApi<TRpcSubscriptionsApiMethods>>['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<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\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<TInboundMessage> = {\n /**\n * Fires when the channel closes unexpectedly.\n * @eventProperty\n */\n error: SolanaError<RpcSubscriptionsChannelSolanaErrorCode>;\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<TInboundMessage>}.\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<TOutboundMessage, TInboundMessage>\n extends DataPublisher<RpcSubscriptionChannelEvents<TInboundMessage>> {\n send(message: TOutboundMessage): Promise<void>;\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<TOutboundMessage, TInboundMessage> = (\n config: Readonly<{\n abortSignal: AbortSignal;\n }>,\n) => Promise<RpcSubscriptionsChannel<TOutboundMessage, TInboundMessage>>;\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<TOutboundMessage, TNewInboundMessage, TInboundMessage>(\n channel: RpcSubscriptionsChannel<TOutboundMessage, TInboundMessage>,\n transform: (message: TInboundMessage) => TNewInboundMessage,\n): RpcSubscriptionsChannel<TOutboundMessage, TNewInboundMessage> {\n return Object.freeze<RpcSubscriptionsChannel<TOutboundMessage, TNewInboundMessage>>({\n ...channel,\n on(type, subscriber, options) {\n if (type !== 'message') {\n return channel.on(\n type,\n subscriber as (data: RpcSubscriptionChannelEvents<TInboundMessage>[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<TNewOutboundMessage, TOutboundMessage, TInboundMessage>(\n channel: RpcSubscriptionsChannel<TOutboundMessage, TInboundMessage>,\n transform: (message: TNewOutboundMessage) => TOutboundMessage,\n): RpcSubscriptionsChannel<TNewOutboundMessage, TInboundMessage> {\n return Object.freeze<RpcSubscriptionsChannel<TNewOutboundMessage, TInboundMessage>>({\n ...channel,\n send: message => channel.send(transform(message)),\n });\n}\n","import { setMaxListeners } from 'node:events';\n\nexport const AbortController = class extends globalThis.AbortController {\n constructor(...args: ConstructorParameters<typeof globalThis.AbortController>) {\n super(...args);\n setMaxListeners(Number.MAX_SAFE_INTEGER, this.signal);\n }\n};\n\nexport const EventTarget = class extends globalThis.EventTarget {\n constructor(...args: ConstructorParameters<typeof globalThis.EventTarget>) {\n super(...args);\n setMaxListeners(Number.MAX_SAFE_INTEGER, this);\n }\n};\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<TNotification> = Readonly<{\n channel: RpcSubscriptionsChannel<unknown, RpcNotification<TNotification> | RpcResponseData<RpcSubscriptionId>>;\n responseTransformer?: RpcResponseTransformer;\n signal: AbortSignal;\n subscribeRequest: RpcRequest;\n unsubscribeMethodName: string;\n}>;\n\ntype RpcNotification<TNotification> = Readonly<{\n method: string;\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\ntype RpcSubscriptionNotificationEvents<TNotification> = Omit<RpcSubscriptionChannelEvents<TNotification>, 'message'> & {\n notification: TNotification;\n};\n\nconst subscriberCountBySubscriptionIdByChannel = new WeakMap<WeakKey, Record<number, number>>();\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 augmentSubscriberCountAndReturnNewCount(\n amount: -1 | 1,\n channel: WeakKey,\n subscriptionId?: number,\n): number | undefined {\n if (subscriptionId === undefined) {\n return;\n }\n let subscriberCountBySubscriptionId = subscriberCountBySubscriptionIdByChannel.get(channel);\n if (!subscriberCountBySubscriptionId && amount > 0) {\n subscriberCountBySubscriptionIdByChannel.set(\n channel,\n (subscriberCountBySubscriptionId = { [subscriptionId]: 0 }),\n );\n }\n if (subscriberCountBySubscriptionId?.[subscriptionId] !== undefined) {\n return (subscriberCountBySubscriptionId[subscriptionId] =\n amount + subscriberCountBySubscriptionId[subscriptionId]);\n }\n}\n\nconst cache = new WeakMap();\nfunction getMemoizedDemultiplexedNotificationPublisherFromChannelAndResponseTransformer<TNotification>(\n channel: RpcSubscriptionsChannel<unknown, RpcNotification<TNotification>>,\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<unknown> | RpcResponseData<unknown>;\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<TNotification>({\n channel,\n responseTransformer,\n signal,\n subscribeRequest,\n unsubscribeMethodName,\n}: Config<TNotification>): Promise<DataPublisher<RpcSubscriptionNotificationEvents<TNotification>>> {\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<never>((_, 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<RpcSubscriptionId>((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<TNotification>['notification']) => void,\n options,\n );\n case 'error':\n return channel.on(\n 'error',\n listener as (data: RpcSubscriptionNotificationEvents<TNotification>['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"]}