@solana/rpc-subscriptions-spec 2.0.0-experimental.080a7d1 → 2.0.0-experimental.0af01ac

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.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var errors = require('@solana/errors');
3
4
  var rpcSpecTypes = require('@solana/rpc-spec-types');
4
5
 
5
6
  // src/rpc-subscriptions.ts
@@ -16,17 +17,17 @@ function makeProxy(rpcConfig) {
16
17
  },
17
18
  get(target, p, receiver) {
18
19
  return function(...rawParams) {
19
- const methodName = p.toString();
20
- const createRpcSubscription = Reflect.get(target, methodName, receiver);
20
+ const notificationName = p.toString();
21
+ const createRpcSubscription = Reflect.get(target, notificationName, receiver);
21
22
  if (p.toString().endsWith("Notifications") === false && !createRpcSubscription) {
22
- throw new Error(
23
- "Either the notification name must end in 'Notifications' or the API must supply a subscription creator function to map between the notification name and the subscribe/unsubscribe method names."
24
- );
23
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {
24
+ notificationName
25
+ });
25
26
  }
26
27
  const newRequest = createRpcSubscription ? createRpcSubscription(...rawParams) : {
27
28
  params: rawParams,
28
- subscribeMethodName: methodName.replace(/Notifications$/, "Subscribe"),
29
- unsubscribeMethodName: methodName.replace(/Notifications$/, "Unsubscribe")
29
+ subscribeMethodName: notificationName.replace(/Notifications$/, "Subscribe"),
30
+ unsubscribeMethodName: notificationName.replace(/Notifications$/, "Unsubscribe")
30
31
  };
31
32
  return createPendingRpcSubscription(rpcConfig, newRequest);
32
33
  };
@@ -81,7 +82,7 @@ function createPendingRpcSubscription(rpcConfig, { params, subscribeMethodName,
81
82
  }
82
83
  }
83
84
  if (subscriptionId == null) {
84
- throw new Error("Failed to obtain a subscription id from the server");
85
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);
85
86
  }
86
87
  return {
87
88
  async *[Symbol.asyncIterator]() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 methodName = p.toString();\n const createRpcSubscription = Reflect.get(target, methodName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n // TODO: Coded error.\n throw new Error(\n \"Either the notification name must end in 'Notifications' or the API \" +\n 'must supply a subscription creator function to map between the ' +\n 'notification name and the subscribe/unsubscribe method names.',\n );\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: methodName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: methodName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n // TODO: Coded error.\n throw new Error('Failed to obtain a subscription id from the server');\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID,\n SolanaError,\n} from '@solana/errors';\nimport {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 createRpcSubscription = Reflect.get(target, notificationName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {\n notificationName,\n });\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: notificationName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: notificationName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { SolanaError, SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID } from '@solana/errors';
1
2
  import { createRpcMessage, RpcError } from '@solana/rpc-spec-types';
2
3
 
3
4
  // src/rpc-subscriptions.ts
@@ -14,17 +15,17 @@ function makeProxy(rpcConfig) {
14
15
  },
15
16
  get(target, p, receiver) {
16
17
  return function(...rawParams) {
17
- const methodName = p.toString();
18
- const createRpcSubscription = Reflect.get(target, methodName, receiver);
18
+ const notificationName = p.toString();
19
+ const createRpcSubscription = Reflect.get(target, notificationName, receiver);
19
20
  if (p.toString().endsWith("Notifications") === false && !createRpcSubscription) {
20
- throw new Error(
21
- "Either the notification name must end in 'Notifications' or the API must supply a subscription creator function to map between the notification name and the subscribe/unsubscribe method names."
22
- );
21
+ throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {
22
+ notificationName
23
+ });
23
24
  }
24
25
  const newRequest = createRpcSubscription ? createRpcSubscription(...rawParams) : {
25
26
  params: rawParams,
26
- subscribeMethodName: methodName.replace(/Notifications$/, "Subscribe"),
27
- unsubscribeMethodName: methodName.replace(/Notifications$/, "Unsubscribe")
27
+ subscribeMethodName: notificationName.replace(/Notifications$/, "Subscribe"),
28
+ unsubscribeMethodName: notificationName.replace(/Notifications$/, "Unsubscribe")
28
29
  };
29
30
  return createPendingRpcSubscription(rpcConfig, newRequest);
30
31
  };
@@ -79,7 +80,7 @@ function createPendingRpcSubscription(rpcConfig, { params, subscribeMethodName,
79
80
  }
80
81
  }
81
82
  if (subscriptionId == null) {
82
- throw new Error("Failed to obtain a subscription id from the server");
83
+ throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);
83
84
  }
84
85
  return {
85
86
  async *[Symbol.asyncIterator]() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 methodName = p.toString();\n const createRpcSubscription = Reflect.get(target, methodName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n // TODO: Coded error.\n throw new Error(\n \"Either the notification name must end in 'Notifications' or the API \" +\n 'must supply a subscription creator function to map between the ' +\n 'notification name and the subscribe/unsubscribe method names.',\n );\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: methodName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: methodName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n // TODO: Coded error.\n throw new Error('Failed to obtain a subscription id from the server');\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID,\n SolanaError,\n} from '@solana/errors';\nimport {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 createRpcSubscription = Reflect.get(target, notificationName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {\n notificationName,\n });\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: notificationName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: notificationName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { SolanaError, SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID } from '@solana/errors';
1
2
  import { createRpcMessage, RpcError } from '@solana/rpc-spec-types';
2
3
 
3
4
  // src/rpc-subscriptions.ts
@@ -14,17 +15,17 @@ function makeProxy(rpcConfig) {
14
15
  },
15
16
  get(target, p, receiver) {
16
17
  return function(...rawParams) {
17
- const methodName = p.toString();
18
- const createRpcSubscription = Reflect.get(target, methodName, receiver);
18
+ const notificationName = p.toString();
19
+ const createRpcSubscription = Reflect.get(target, notificationName, receiver);
19
20
  if (p.toString().endsWith("Notifications") === false && !createRpcSubscription) {
20
- throw new Error(
21
- "Either the notification name must end in 'Notifications' or the API must supply a subscription creator function to map between the notification name and the subscribe/unsubscribe method names."
22
- );
21
+ throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {
22
+ notificationName
23
+ });
23
24
  }
24
25
  const newRequest = createRpcSubscription ? createRpcSubscription(...rawParams) : {
25
26
  params: rawParams,
26
- subscribeMethodName: methodName.replace(/Notifications$/, "Subscribe"),
27
- unsubscribeMethodName: methodName.replace(/Notifications$/, "Unsubscribe")
27
+ subscribeMethodName: notificationName.replace(/Notifications$/, "Subscribe"),
28
+ unsubscribeMethodName: notificationName.replace(/Notifications$/, "Unsubscribe")
28
29
  };
29
30
  return createPendingRpcSubscription(rpcConfig, newRequest);
30
31
  };
@@ -79,7 +80,7 @@ function createPendingRpcSubscription(rpcConfig, { params, subscribeMethodName,
79
80
  }
80
81
  }
81
82
  if (subscriptionId == null) {
82
- throw new Error("Failed to obtain a subscription id from the server");
83
+ throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);
83
84
  }
84
85
  return {
85
86
  async *[Symbol.asyncIterator]() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 methodName = p.toString();\n const createRpcSubscription = Reflect.get(target, methodName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n // TODO: Coded error.\n throw new Error(\n \"Either the notification name must end in 'Notifications' or the API \" +\n 'must supply a subscription creator function to map between the ' +\n 'notification name and the subscribe/unsubscribe method names.',\n );\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: methodName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: methodName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n // TODO: Coded error.\n throw new Error('Failed to obtain a subscription id from the server');\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID,\n SolanaError,\n} from '@solana/errors';\nimport {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 createRpcSubscription = Reflect.get(target, notificationName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {\n notificationName,\n });\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: notificationName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: notificationName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var errors = require('@solana/errors');
3
4
  var rpcSpecTypes = require('@solana/rpc-spec-types');
4
5
 
5
6
  // src/rpc-subscriptions.ts
@@ -16,17 +17,17 @@ function makeProxy(rpcConfig) {
16
17
  },
17
18
  get(target, p, receiver) {
18
19
  return function(...rawParams) {
19
- const methodName = p.toString();
20
- const createRpcSubscription = Reflect.get(target, methodName, receiver);
20
+ const notificationName = p.toString();
21
+ const createRpcSubscription = Reflect.get(target, notificationName, receiver);
21
22
  if (p.toString().endsWith("Notifications") === false && !createRpcSubscription) {
22
- throw new Error(
23
- "Either the notification name must end in 'Notifications' or the API must supply a subscription creator function to map between the notification name and the subscribe/unsubscribe method names."
24
- );
23
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {
24
+ notificationName
25
+ });
25
26
  }
26
27
  const newRequest = createRpcSubscription ? createRpcSubscription(...rawParams) : {
27
28
  params: rawParams,
28
- subscribeMethodName: methodName.replace(/Notifications$/, "Subscribe"),
29
- unsubscribeMethodName: methodName.replace(/Notifications$/, "Unsubscribe")
29
+ subscribeMethodName: notificationName.replace(/Notifications$/, "Subscribe"),
30
+ unsubscribeMethodName: notificationName.replace(/Notifications$/, "Unsubscribe")
30
31
  };
31
32
  return createPendingRpcSubscription(rpcConfig, newRequest);
32
33
  };
@@ -81,7 +82,7 @@ function createPendingRpcSubscription(rpcConfig, { params, subscribeMethodName,
81
82
  }
82
83
  }
83
84
  if (subscriptionId == null) {
84
- throw new Error("Failed to obtain a subscription id from the server");
85
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);
85
86
  }
86
87
  return {
87
88
  async *[Symbol.asyncIterator]() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 methodName = p.toString();\n const createRpcSubscription = Reflect.get(target, methodName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n // TODO: Coded error.\n throw new Error(\n \"Either the notification name must end in 'Notifications' or the API \" +\n 'must supply a subscription creator function to map between the ' +\n 'notification name and the subscribe/unsubscribe method names.',\n );\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: methodName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: methodName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n // TODO: Coded error.\n throw new Error('Failed to obtain a subscription id from the server');\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID,\n SolanaError,\n} from '@solana/errors';\nimport {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 createRpcSubscription = Reflect.get(target, notificationName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {\n notificationName,\n });\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: notificationName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: notificationName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { SolanaError, SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID } from '@solana/errors';
1
2
  import { createRpcMessage, RpcError } from '@solana/rpc-spec-types';
2
3
 
3
4
  // src/rpc-subscriptions.ts
@@ -14,17 +15,17 @@ function makeProxy(rpcConfig) {
14
15
  },
15
16
  get(target, p, receiver) {
16
17
  return function(...rawParams) {
17
- const methodName = p.toString();
18
- const createRpcSubscription = Reflect.get(target, methodName, receiver);
18
+ const notificationName = p.toString();
19
+ const createRpcSubscription = Reflect.get(target, notificationName, receiver);
19
20
  if (p.toString().endsWith("Notifications") === false && !createRpcSubscription) {
20
- throw new Error(
21
- "Either the notification name must end in 'Notifications' or the API must supply a subscription creator function to map between the notification name and the subscribe/unsubscribe method names."
22
- );
21
+ throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {
22
+ notificationName
23
+ });
23
24
  }
24
25
  const newRequest = createRpcSubscription ? createRpcSubscription(...rawParams) : {
25
26
  params: rawParams,
26
- subscribeMethodName: methodName.replace(/Notifications$/, "Subscribe"),
27
- unsubscribeMethodName: methodName.replace(/Notifications$/, "Unsubscribe")
27
+ subscribeMethodName: notificationName.replace(/Notifications$/, "Subscribe"),
28
+ unsubscribeMethodName: notificationName.replace(/Notifications$/, "Unsubscribe")
28
29
  };
29
30
  return createPendingRpcSubscription(rpcConfig, newRequest);
30
31
  };
@@ -79,7 +80,7 @@ function createPendingRpcSubscription(rpcConfig, { params, subscribeMethodName,
79
80
  }
80
81
  }
81
82
  if (subscriptionId == null) {
82
- throw new Error("Failed to obtain a subscription id from the server");
83
+ throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);
83
84
  }
84
85
  return {
85
86
  async *[Symbol.asyncIterator]() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":";AAAA;AAAA,EAEI;AAAA,EAGA;AAAA,OAGG;AAiDA,SAAS,sBAIZ,WAC6C;AAC7C,SAAO,UAAU,SAAS;AAC9B;AAEA,SAAS,UACL,WAC6C;AAC7C,SAAO,IAAI,MAAM,UAAU,KAAK;AAAA,IAC5B,iBAAiB;AACb,aAAO;AAAA,IACX;AAAA,IACA,iBAAiB;AACb,aAAO;AAAA,IACX;AAAA,IACA,IAAI,QAAQ,GAAG,UAAU;AACrB,aAAO,YAAa,WAAsB;AACtC,cAAM,aAAa,EAAE,SAAS;AAC9B,cAAM,wBAAwB,QAAQ,IAAI,QAAQ,YAAY,QAAQ;AACtE,YAAI,EAAE,SAAS,EAAE,SAAS,eAAe,MAAM,SAAS,CAAC,uBAAuB;AAE5E,gBAAM,IAAI;AAAA,YACN;AAAA,UAGJ;AAAA,QACJ;AACA,cAAM,aAAa,wBACb,sBAAsB,GAAG,SAAS,IAClC;AAAA,UACI,QAAQ;AAAA,UACR,qBAAqB,WAAW,QAAQ,kBAAkB,WAAW;AAAA,UACrE,uBAAuB,WAAW,QAAQ,kBAAkB,aAAa;AAAA,QAC7E;AACN,eAAO,6BAA6B,WAAW,UAAU;AAAA,MAC7D;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAEA,SAAS,wBAAwB,UAAkC,WAA6B;AAC5F,GAAC,YAAY;AACT,QAAI;AAEA,uBAAiB,KAAK;AAAS;AAAA,IACnC,QAAQ;AAAA,IAER,UAAE;AAEE,gBAAU;AAAA,IACd;AAAA,EACJ,GAAG;AACP;AAEA,SAAS,6BAKL,WACA,EAAE,QAAQ,qBAAqB,uBAAuB,oBAAoB,GAC7B;AAC7C,SAAO;AAAA,IACH,MAAM,UAAU,EAAE,YAAY,GAA+D;AACzF,kBAAY,eAAe;AAC3B,UAAI;AACJ,eAAS,gBAAgB;AACrB,YAAI,mBAAmB,QAAW;AAC9B,gBAAM,UAAU,iBAAiB,uBAAuB,CAAC,cAAc,CAAC;AACxE,qBAAW,qCAAqC,OAAO,EAAE,QAAQ,MAAM;AACnE,sCAA0B,MAAM;AAAA,UACpC,CAAC;AAAA,QACL,OAAO;AACH,oCAA0B,MAAM;AAAA,QACpC;AAAA,MACJ;AACA,kBAAY,iBAAiB,SAAS,aAAa;AAInD,YAAM,4BAA4B,IAAI,gBAAgB;AACtD,YAAM,mBAAmB,iBAAiB,qBAAqB,MAAM;AACrE,YAAM,aAAa,MAAM,UAAU,UAAU;AAAA,QACzC,SAAS;AAAA,QACT,QAAQ,0BAA0B;AAAA,MACtC,CAAC;AACD,eAAS,0BAA0B;AAC/B,oBAAY,oBAAoB,SAAS,aAAa;AAAA,MAC1D;AACA,8BAAwB,YAAY,uBAAuB;AAI3D,uBAAiB,WAAW,YAEzB;AACC,YAAI,QAAQ,WAAW,QAAQ,OAAO,iBAAiB,IAAI;AACvD,cAAI,WAAW,SAAS;AACpB,kBAAM,IAAI,SAAS,QAAQ,KAAK;AAAA,UACpC,OAAO;AACH,6BAAiB,QAAQ;AACzB;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AACA,UAAI,kBAAkB,MAAM;AAExB,cAAM,IAAI,MAAM,oDAAoD;AAAA,MACxE;AAIA,aAAO;AAAA,QACH,QAAQ,OAAO,aAAa,IAAI;AAC5B,2BAAiB,WAAW,YAEzB;AACC,gBAAI,EAAE,YAAY,YAAY,QAAQ,OAAO,iBAAiB,gBAAgB;AAC1E;AAAA,YACJ;AACA,kBAAM,eAAe,QAAQ,OAAO;AACpC,kBAAM,sBACA,oBAAoB,cAAc,mBAAmB,IACrD;AAAA,UACV;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;ACnKO,SAAS,0BACZ,QACgD;AAChD,SAAO,IAAI,MAAM,CAAC,GAAuD;AAAA,IACrE,iBAAiB;AACb,aAAO;AAAA,IACX;AAAA,IACA,iBAAiB;AACb,aAAO;AAAA,IACX;AAAA,IACA,OACO,MACL;AACE,YAAM,CAAC,GAAG,CAAC,IAAI;AACf,YAAM,mBAAmB,EAAE,SAAS;AACpC,aAAO,YACA,WAKgF;AACnF,cAAM,SAAS,QAAQ,wBACjB,QAAQ,sBAAsB,WAAW,gBAAgB,IACzD;AACN,cAAM,sBAAsB,QAAQ,sBAC9B,QAAQ,sBACR,CAAC,gBACG;AACV,cAAM,sBAAsB,QAAQ,uCAC9B,QAAQ,qCAAqC,gBAAgB,IAC7D;AACN,cAAM,wBAAwB,QAAQ,yCAChC,QAAQ,uCAAuC,gBAAgB,IAC/D;AACN,eAAO;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ,CAAC;AACL","sourcesContent":["import {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 methodName = p.toString();\n const createRpcSubscription = Reflect.get(target, methodName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n // TODO: Coded error.\n throw new Error(\n \"Either the notification name must end in 'Notifications' or the API \" +\n 'must supply a subscription creator function to map between the ' +\n 'notification name and the subscribe/unsubscribe method names.',\n );\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: methodName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: methodName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n // TODO: Coded error.\n throw new Error('Failed to obtain a subscription id from the server');\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/rpc-subscriptions.ts","../src/rpc-subscriptions-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST,\n SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID,\n SolanaError,\n} from '@solana/errors';\nimport {\n Callable,\n createRpcMessage,\n Flatten,\n OverloadImplementations,\n RpcError,\n RpcResponse,\n UnionToIntersection,\n} from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsApi } from './rpc-subscriptions-api';\nimport {\n PendingRpcSubscriptionsRequest,\n RpcSubscribeOptions,\n RpcSubscriptionsRequest,\n} from './rpc-subscriptions-request';\nimport { RpcSubscriptionsTransport } from './rpc-subscriptions-transport';\n\nexport type RpcSubscriptionsConfig<\n TRpcMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n> = Readonly<{\n api: RpcSubscriptionsApi<TRpcMethods>;\n transport: TRpcSubscriptionsTransport;\n}>;\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\ntype RpcNotification<TNotification> = Readonly<{\n params: Readonly<{\n result: TNotification;\n subscription: number;\n }>;\n}>;\n\ntype RpcSubscriptionId = number;\n\nexport function createSubscriptionRpc<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n): RpcSubscriptions<TRpcSubscriptionsApiMethods> {\n return makeProxy(rpcConfig);\n}\n\nfunction makeProxy<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport extends RpcSubscriptionsTransport>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\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 createRpcSubscription = Reflect.get(target, notificationName, receiver);\n if (p.toString().endsWith('Notifications') === false && !createRpcSubscription) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_CANNOT_CREATE_SUBSCRIPTION_REQUEST, {\n notificationName,\n });\n }\n const newRequest = createRpcSubscription\n ? createRpcSubscription(...rawParams)\n : {\n params: rawParams,\n subscribeMethodName: notificationName.replace(/Notifications$/, 'Subscribe'),\n unsubscribeMethodName: notificationName.replace(/Notifications$/, 'Unsubscribe'),\n };\n return createPendingRpcSubscription(rpcConfig, newRequest);\n };\n },\n }) as RpcSubscriptions<TRpcSubscriptionsApiMethods>;\n}\n\nfunction registerIterableCleanup(iterable: AsyncIterable<unknown>, cleanupFn: CallableFunction) {\n (async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _ of iterable);\n } catch {\n /* empty */\n } finally {\n // Run the cleanup function.\n cleanupFn();\n }\n })();\n}\n\nfunction createPendingRpcSubscription<\n TRpcSubscriptionsApiMethods,\n TRpcSubscriptionsTransport extends RpcSubscriptionsTransport,\n TNotification,\n>(\n rpcConfig: RpcSubscriptionsConfig<TRpcSubscriptionsApiMethods, TRpcSubscriptionsTransport>,\n { params, subscribeMethodName, unsubscribeMethodName, responseTransformer }: RpcSubscriptionsRequest<TNotification>,\n): PendingRpcSubscriptionsRequest<TNotification> {\n return {\n async subscribe({ abortSignal }: RpcSubscribeOptions): Promise<AsyncIterable<TNotification>> {\n abortSignal.throwIfAborted();\n let subscriptionId: number | undefined;\n function handleCleanup() {\n if (subscriptionId !== undefined) {\n const payload = createRpcMessage(unsubscribeMethodName, [subscriptionId]);\n connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload).finally(() => {\n connectionAbortController.abort();\n });\n } else {\n connectionAbortController.abort();\n }\n }\n abortSignal.addEventListener('abort', handleCleanup);\n /**\n * STEP 1: Send the subscribe message.\n */\n const connectionAbortController = new AbortController();\n const subscribeMessage = createRpcMessage(subscribeMethodName, params);\n const connection = await rpcConfig.transport({\n payload: subscribeMessage,\n signal: connectionAbortController.signal,\n });\n function handleConnectionCleanup() {\n abortSignal.removeEventListener('abort', handleCleanup);\n }\n registerIterableCleanup(connection, handleConnectionCleanup);\n /**\n * STEP 2: Wait for the acknowledgement from the server with the subscription id.\n */\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if ('id' in message && message.id === subscribeMessage.id) {\n if ('error' in message) {\n throw new RpcError(message.error);\n } else {\n subscriptionId = message.result as RpcSubscriptionId;\n break;\n }\n }\n }\n if (subscriptionId == null) {\n throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS_EXPECTED_SERVER_SUBSCRIPTION_ID);\n }\n /**\n * STEP 3: Return an iterable that yields notifications for this subscription id.\n */\n return {\n async *[Symbol.asyncIterator]() {\n for await (const message of connection as AsyncIterable<\n RpcNotification<unknown> | RpcResponse<RpcSubscriptionId>\n >) {\n if (!('params' in message) || message.params.subscription !== subscriptionId) {\n continue;\n }\n const notification = message.params.result as TNotification;\n yield responseTransformer\n ? responseTransformer(notification, subscribeMethodName)\n : notification;\n }\n },\n };\n },\n };\n}\n","import { Callable } from '@solana/rpc-spec-types';\n\nimport { RpcSubscriptionsRequest } from './rpc-subscriptions-request';\n\nexport type RpcSubscriptionsApiConfig = Readonly<{\n parametersTransformer?: <T extends unknown[]>(params: T, notificationName: string) => unknown[];\n responseTransformer?: <T>(response: unknown, notificationName: string) => T;\n subscribeNotificationNameTransformer?: (notificationName: string) => string;\n unsubscribeNotificationNameTransformer?: (notificationName: string) => string;\n}>;\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[]) => RpcSubscriptionsRequest<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\nexport function createRpcSubscriptionsApi<TRpcSubscriptionsApiMethods extends RpcSubscriptionsApiMethods>(\n config?: RpcSubscriptionsApiConfig,\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 notificationName = p.toString() as keyof TRpcSubscriptionsApiMethods as string;\n return function (\n ...rawParams: Parameters<\n TRpcSubscriptionsApiMethods[TNotificationName] extends CallableFunction\n ? TRpcSubscriptionsApiMethods[TNotificationName]\n : never\n >\n ): RpcSubscriptionsRequest<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>> {\n const params = config?.parametersTransformer\n ? config?.parametersTransformer(rawParams, notificationName)\n : rawParams;\n const responseTransformer = config?.responseTransformer\n ? config?.responseTransformer<ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>>\n : (rawResponse: unknown) =>\n rawResponse as ReturnType<TRpcSubscriptionsApiMethods[TNotificationName]>;\n const subscribeMethodName = config?.subscribeNotificationNameTransformer\n ? config?.subscribeNotificationNameTransformer(notificationName)\n : notificationName;\n const unsubscribeMethodName = config?.unsubscribeNotificationNameTransformer\n ? config?.unsubscribeNotificationNameTransformer(notificationName)\n : notificationName;\n return {\n params,\n responseTransformer,\n subscribeMethodName,\n unsubscribeMethodName,\n };\n };\n },\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-subscriptions.d.ts","sourceRoot":"","sources":["../../src/rpc-subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EAER,OAAO,EACP,uBAAuB,EAGvB,mBAAmB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EACH,8BAA8B,EAGjC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,MAAM,MAAM,sBAAsB,CAC9B,WAAW,EACX,0BAA0B,SAAS,yBAAyB,IAC5D,QAAQ,CAAC;IACT,GAAG,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACtC,SAAS,EAAE,0BAA0B,CAAC;CACzC,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,CAAC,wBAAwB,IAAI;KACpD,WAAW,IAAI,MAAM,wBAAwB,GAAG,qCAAqC,CAClF,uBAAuB,CAAC,wBAAwB,EAAE,WAAW,CAAC,CACjE;CACJ,CAAC;AAEF,KAAK,qCAAqC,CAAC,kCAAkC,IAAI,mBAAmB,CAChG,OAAO,CAAC;KACH,CAAC,IAAI,MAAM,kCAAkC,GAAG,8CAA8C,CAC3F,kCAAkC,CAAC,CAAC,CAAC,CACxC;CACJ,CAAC,CACL,CAAC;AAEF,KAAK,8CAA8C,CAAC,iCAAiC,IAEjF,iCAAiC,SAAS,QAAQ,GAC5C,CACI,GAAG,IAAI,EAAE,UAAU,CAAC,iCAAiC,CAAC,KACrD,8BAA8B,CAAC,UAAU,CAAC,iCAAiC,CAAC,CAAC,GAClF,KAAK,CAAC;AAWhB,wBAAgB,qBAAqB,CACjC,2BAA2B,EAC3B,0BAA0B,SAAS,yBAAyB,EAE5D,SAAS,EAAE,sBAAsB,CAAC,2BAA2B,EAAE,0BAA0B,CAAC,GAC3F,gBAAgB,CAAC,2BAA2B,CAAC,CAE/C"}
1
+ {"version":3,"file":"rpc-subscriptions.d.ts","sourceRoot":"","sources":["../../src/rpc-subscriptions.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,QAAQ,EAER,OAAO,EACP,uBAAuB,EAGvB,mBAAmB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EACH,8BAA8B,EAGjC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,MAAM,MAAM,sBAAsB,CAC9B,WAAW,EACX,0BAA0B,SAAS,yBAAyB,IAC5D,QAAQ,CAAC;IACT,GAAG,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACtC,SAAS,EAAE,0BAA0B,CAAC;CACzC,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,CAAC,wBAAwB,IAAI;KACpD,WAAW,IAAI,MAAM,wBAAwB,GAAG,qCAAqC,CAClF,uBAAuB,CAAC,wBAAwB,EAAE,WAAW,CAAC,CACjE;CACJ,CAAC;AAEF,KAAK,qCAAqC,CAAC,kCAAkC,IAAI,mBAAmB,CAChG,OAAO,CAAC;KACH,CAAC,IAAI,MAAM,kCAAkC,GAAG,8CAA8C,CAC3F,kCAAkC,CAAC,CAAC,CAAC,CACxC;CACJ,CAAC,CACL,CAAC;AAEF,KAAK,8CAA8C,CAAC,iCAAiC,IAEjF,iCAAiC,SAAS,QAAQ,GAC5C,CACI,GAAG,IAAI,EAAE,UAAU,CAAC,iCAAiC,CAAC,KACrD,8BAA8B,CAAC,UAAU,CAAC,iCAAiC,CAAC,CAAC,GAClF,KAAK,CAAC;AAWhB,wBAAgB,qBAAqB,CACjC,2BAA2B,EAC3B,0BAA0B,SAAS,yBAAyB,EAE5D,SAAS,EAAE,sBAAsB,CAAC,2BAA2B,EAAE,0BAA0B,CAAC,GAC3F,gBAAgB,CAAC,2BAA2B,CAAC,CAE/C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/rpc-subscriptions-spec",
3
- "version": "2.0.0-experimental.080a7d1",
3
+ "version": "2.0.0-experimental.0af01ac",
4
4
  "description": "A generic implementation of JSON RPC Subscriptions using proxies",
5
5
  "exports": {
6
6
  "browser": {
@@ -46,7 +46,8 @@
46
46
  "maintained node versions"
47
47
  ],
48
48
  "dependencies": {
49
- "@solana/rpc-spec-types": "2.0.0-experimental.080a7d1"
49
+ "@solana/errors": "2.0.0-experimental.0af01ac",
50
+ "@solana/rpc-spec-types": "2.0.0-experimental.0af01ac"
50
51
  },
51
52
  "bundlewatch": {
52
53
  "defaultCompression": "gzip",