@solana/plugin-core 6.10.0-canary-20260514084615 → 6.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.browser.cjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): Omit<TClient, keyof TAdditions> & TAdditions {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n */\nexport function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as Disposable & TClient;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as Disposable & TClient;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;AAqJO,IAAM,iBAAA,GAAoB,MAAM,YAAA;AAyBhC,SAAS,aAA4C,KAAA,EAA8B;AACtF,EAAA,OAAO,MAAA,CAAO,KAAA,IAAU,EAAY,CAAA;AACxC;AAEA,SAAS,OAA6B,KAAA,EAA6B;AAC/D,EAAA,OAAO,MAAA,CAAO,MAAA;AAAA,IACV,MAAA,CAAO,gBAAA;AAAA,MACH,EAAC;AAAA,MACD;AAAA,QACI,GAAG,MAAA,CAAO,yBAAA,CAA0B,KAAK,CAAA;AAAA,QACzC,GAAA,EAAK;AAAA,UACD,YAAA,EAAc,KAAA;AAAA,UACd,UAAA,EAAY,IAAA;AAAA,UACZ,KAAA,EAAO,SAAoD,MAAA,EAAsC;AAC7F,YAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAC3B,YAAA,OAAO,kBAAkB,OAAA,GAAU,iBAAA,CAAkB,MAAM,CAAA,GAAI,OAAO,MAAM,CAAA;AAAA,UAChF,CAAA;AAAA,UACA,QAAA,EAAU;AAAA;AACd;AACJ;AACJ,GACJ;AACJ;AAEA,SAAS,kBAAwC,OAAA,EAA6C;AAC1F,EAAA,OAAO,OAAO,MAAA,CAAO;AAAA,IACjB,MAAM,UAAA,EAAY;AACd,MAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,MAAM,UAAU,CAAA;AAAA,IACxD,CAAA;AAAA,IACA,QAAQ,SAAA,EAAW;AACf,MAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,QAAQ,SAAS,CAAA;AAAA,IACzD,CAAA;AAAA,IACA,IAAA,CAAK,aAAa,UAAA,EAAY;AAC1B,MAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,WAAA,EAAa,UAAU,CAAA;AAAA,IACpE,CAAA;AAAA,IACA,IAA8C,MAAA,EAAsC;AAChF,MAAA,OAAO,iBAAA,CAAkB,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,IACjD;AAAA,GACmB,CAAA;AAC3B;AA2DO,SAAS,YAAA,CACZ,QACA,SAAA,EACmC;AACnC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,gBAAA,CAAiB,EAAC,EAAG,0BAA0B,MAAA,CAAO,yBAAA,CAA0B,MAAM,CAAC,CAAC,CAAA;AAC9G,EAAA,MAAA,CAAO,gBAAA,CAAiB,MAAA,EAAQ,MAAA,CAAO,yBAAA,CAA0B,SAAS,CAAC,CAAA;AAC3E,EAAA,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAC/B;AAEA,SAAS,0BAA2D,WAAA,EAAmB;AACnF,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,GAAA,IAAO,OAAA,CAAQ,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC5C,IAAA,MAAA,CAAO,GAAG,IAAI,EAAE,GAAG,YAAY,GAAc,CAAA,EAAG,cAAc,IAAA,EAAK;AAAA,EACvE;AACA,EAAA,OAAO,MAAA;AACX;AAwCO,SAAS,WAAA,CACZ,QACA,OAAA,EACmC;AACnC,EAAA,IAAI,6BAA6B,MAAA,EAAQ;AACrC,IAAA,OAAO,mCAAA;AAAA,MACH,MAAA;AAAA,MACA;AAAA,KACJ;AAAA,EACJ,CAAA,MAAO;AACH,IAAA,OAAO,sCAAA,CAAuC,QAAQ,OAAO,CAAA;AAAA,EACjE;AACJ;AAEA,IAAM,yBAAA,GAA4B,6BAAA;AAElC,SAAS,mCAAA,CACL,QACA,OAAA,EACmC;AAEnC,EAAA,MAAA,CAAO,yBAAyB,CAAA,CAAE,KAAA,CAAM,OAAO,CAAA;AAE/C,EAAA,OAAO,MAAA;AACX;AAEA,SAAS,sCAAA,CACL,QACA,OAAA,EACmC;AACnC,EAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,EAAgB;AAGlC,EAAA,IAAI,MAAA,CAAO,WAAW,MAAA,EAAQ;AAC1B,IAAA,MAAM,eAAA,GAAmB,MAAA,CAAsB,MAAA,CAAO,OAAO,CAAA;AAC7D,IAAA,KAAA,CAAM,KAAA,CAAM,MAAM,eAAA,CAAgB,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,EAClD;AAGA,EAAA,KAAA,CAAM,MAAM,OAAO,CAAA;AAGnB,EAAA,MAAM,SAAA,GAAY;AAAA,IACd,CAAC,yBAAyB,GAAG,KAAA;AAAA,IAC7B,CAAC,MAAA,CAAO,OAAO,CAAA,GAAI;AACf,MAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,IAC1B;AAAA,GACJ;AAEA,EAAA,OAAO,YAAA,CAAa,QAAQ,SAAS,CAAA;AACzC","file":"index.browser.cjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.\n *\n * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present\n * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed\n * as a single homomorphic mapped type so the inferred type displays as a flat object literal\n * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`\n * modifiers from both sides are preserved.\n *\n * Plugin authors who write their own merging helpers can reuse this type to keep the\n * inferred shape of their plugin's output legible in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the client being extended.\n * @typeParam TAdditions - The type of the properties being merged in.\n *\n * @example\n * ```ts\n * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {\n * return extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link extendClient}\n */\nexport type ExtendedClient<TClient extends object, TAdditions extends object> = {\n [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];\n} & {};\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single\n * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers\n * in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n * @see {@link ExtendedClient}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): ExtendedClient<TClient, TAdditions> {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as ExtendedClient<TClient, TAdditions>;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a\n * single object literal so chained calls do not accumulate nested intersections in editor\n * tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n * @see {@link ExtendedClient}\n */\nexport function withCleanup<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as unknown as ExtendedClient<TClient, Disposable>;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as ExtendedClient<TClient, Disposable>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.browser.mjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): Omit<TClient, keyof TAdditions> & TAdditions {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n */\nexport function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as Disposable & TClient;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as Disposable & TClient;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.browser.mjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.\n *\n * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present\n * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed\n * as a single homomorphic mapped type so the inferred type displays as a flat object literal\n * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`\n * modifiers from both sides are preserved.\n *\n * Plugin authors who write their own merging helpers can reuse this type to keep the\n * inferred shape of their plugin's output legible in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the client being extended.\n * @typeParam TAdditions - The type of the properties being merged in.\n *\n * @example\n * ```ts\n * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {\n * return extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link extendClient}\n */\nexport type ExtendedClient<TClient extends object, TAdditions extends object> = {\n [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];\n} & {};\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single\n * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers\n * in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n * @see {@link ExtendedClient}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): ExtendedClient<TClient, TAdditions> {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as ExtendedClient<TClient, TAdditions>;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a\n * single object literal so chained calls do not accumulate nested intersections in editor\n * tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n * @see {@link ExtendedClient}\n */\nexport function withCleanup<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as unknown as ExtendedClient<TClient, Disposable>;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as ExtendedClient<TClient, Disposable>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.native.mjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): Omit<TClient, keyof TAdditions> & TAdditions {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n */\nexport function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as Disposable & TClient;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as Disposable & TClient;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.native.mjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.\n *\n * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present\n * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed\n * as a single homomorphic mapped type so the inferred type displays as a flat object literal\n * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`\n * modifiers from both sides are preserved.\n *\n * Plugin authors who write their own merging helpers can reuse this type to keep the\n * inferred shape of their plugin's output legible in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the client being extended.\n * @typeParam TAdditions - The type of the properties being merged in.\n *\n * @example\n * ```ts\n * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {\n * return extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link extendClient}\n */\nexport type ExtendedClient<TClient extends object, TAdditions extends object> = {\n [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];\n} & {};\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single\n * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers\n * in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n * @see {@link ExtendedClient}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): ExtendedClient<TClient, TAdditions> {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as ExtendedClient<TClient, TAdditions>;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a\n * single object literal so chained calls do not accumulate nested intersections in editor\n * tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n * @see {@link ExtendedClient}\n */\nexport function withCleanup<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as unknown as ExtendedClient<TClient, Disposable>;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as ExtendedClient<TClient, Disposable>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.node.cjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): Omit<TClient, keyof TAdditions> & TAdditions {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n */\nexport function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as Disposable & TClient;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as Disposable & TClient;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;AAqJO,IAAM,iBAAA,GAAoB,MAAM,YAAA;AAyBhC,SAAS,aAA4C,KAAA,EAA8B;AACtF,EAAA,OAAO,MAAA,CAAO,KAAA,IAAU,EAAY,CAAA;AACxC;AAEA,SAAS,OAA6B,KAAA,EAA6B;AAC/D,EAAA,OAAO,MAAA,CAAO,MAAA;AAAA,IACV,MAAA,CAAO,gBAAA;AAAA,MACH,EAAC;AAAA,MACD;AAAA,QACI,GAAG,MAAA,CAAO,yBAAA,CAA0B,KAAK,CAAA;AAAA,QACzC,GAAA,EAAK;AAAA,UACD,YAAA,EAAc,KAAA;AAAA,UACd,UAAA,EAAY,IAAA;AAAA,UACZ,KAAA,EAAO,SAAoD,MAAA,EAAsC;AAC7F,YAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAC3B,YAAA,OAAO,kBAAkB,OAAA,GAAU,iBAAA,CAAkB,MAAM,CAAA,GAAI,OAAO,MAAM,CAAA;AAAA,UAChF,CAAA;AAAA,UACA,QAAA,EAAU;AAAA;AACd;AACJ;AACJ,GACJ;AACJ;AAEA,SAAS,kBAAwC,OAAA,EAA6C;AAC1F,EAAA,OAAO,OAAO,MAAA,CAAO;AAAA,IACjB,MAAM,UAAA,EAAY;AACd,MAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,MAAM,UAAU,CAAA;AAAA,IACxD,CAAA;AAAA,IACA,QAAQ,SAAA,EAAW;AACf,MAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,QAAQ,SAAS,CAAA;AAAA,IACzD,CAAA;AAAA,IACA,IAAA,CAAK,aAAa,UAAA,EAAY;AAC1B,MAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,WAAA,EAAa,UAAU,CAAA;AAAA,IACpE,CAAA;AAAA,IACA,IAA8C,MAAA,EAAsC;AAChF,MAAA,OAAO,iBAAA,CAAkB,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,IACjD;AAAA,GACmB,CAAA;AAC3B;AA2DO,SAAS,YAAA,CACZ,QACA,SAAA,EACmC;AACnC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,gBAAA,CAAiB,EAAC,EAAG,0BAA0B,MAAA,CAAO,yBAAA,CAA0B,MAAM,CAAC,CAAC,CAAA;AAC9G,EAAA,MAAA,CAAO,gBAAA,CAAiB,MAAA,EAAQ,MAAA,CAAO,yBAAA,CAA0B,SAAS,CAAC,CAAA;AAC3E,EAAA,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAC/B;AAEA,SAAS,0BAA2D,WAAA,EAAmB;AACnF,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,GAAA,IAAO,OAAA,CAAQ,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC5C,IAAA,MAAA,CAAO,GAAG,IAAI,EAAE,GAAG,YAAY,GAAc,CAAA,EAAG,cAAc,IAAA,EAAK;AAAA,EACvE;AACA,EAAA,OAAO,MAAA;AACX;AAwCO,SAAS,WAAA,CACZ,QACA,OAAA,EACmC;AACnC,EAAA,IAAI,6BAA6B,MAAA,EAAQ;AACrC,IAAA,OAAO,mCAAA;AAAA,MACH,MAAA;AAAA,MACA;AAAA,KACJ;AAAA,EACJ,CAAA,MAAO;AACH,IAAA,OAAO,sCAAA,CAAuC,QAAQ,OAAO,CAAA;AAAA,EACjE;AACJ;AAEA,IAAM,yBAAA,GAA4B,6BAAA;AAElC,SAAS,mCAAA,CACL,QACA,OAAA,EACmC;AAEnC,EAAA,MAAA,CAAO,yBAAyB,CAAA,CAAE,KAAA,CAAM,OAAO,CAAA;AAE/C,EAAA,OAAO,MAAA;AACX;AAEA,SAAS,sCAAA,CACL,QACA,OAAA,EACmC;AACnC,EAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,EAAgB;AAGlC,EAAA,IAAI,MAAA,CAAO,WAAW,MAAA,EAAQ;AAC1B,IAAA,MAAM,eAAA,GAAmB,MAAA,CAAsB,MAAA,CAAO,OAAO,CAAA;AAC7D,IAAA,KAAA,CAAM,KAAA,CAAM,MAAM,eAAA,CAAgB,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,EAClD;AAGA,EAAA,KAAA,CAAM,MAAM,OAAO,CAAA;AAGnB,EAAA,MAAM,SAAA,GAAY;AAAA,IACd,CAAC,yBAAyB,GAAG,KAAA;AAAA,IAC7B,CAAC,MAAA,CAAO,OAAO,CAAA,GAAI;AACf,MAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,IAC1B;AAAA,GACJ;AAEA,EAAA,OAAO,YAAA,CAAa,QAAQ,SAAS,CAAA;AACzC","file":"index.node.cjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.\n *\n * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present\n * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed\n * as a single homomorphic mapped type so the inferred type displays as a flat object literal\n * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`\n * modifiers from both sides are preserved.\n *\n * Plugin authors who write their own merging helpers can reuse this type to keep the\n * inferred shape of their plugin's output legible in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the client being extended.\n * @typeParam TAdditions - The type of the properties being merged in.\n *\n * @example\n * ```ts\n * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {\n * return extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link extendClient}\n */\nexport type ExtendedClient<TClient extends object, TAdditions extends object> = {\n [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];\n} & {};\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single\n * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers\n * in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n * @see {@link ExtendedClient}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): ExtendedClient<TClient, TAdditions> {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as ExtendedClient<TClient, TAdditions>;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a\n * single object literal so chained calls do not accumulate nested intersections in editor\n * tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n * @see {@link ExtendedClient}\n */\nexport function withCleanup<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as unknown as ExtendedClient<TClient, Disposable>;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as ExtendedClient<TClient, Disposable>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.node.mjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): Omit<TClient, keyof TAdditions> & TAdditions {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n */\nexport function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as Disposable & TClient;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): Disposable & TClient {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as Disposable & TClient;\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.node.mjs","sourcesContent":["/**\n * Defines a plugin that transforms or extends a client with additional functionality.\n *\n * For instance, plugins may add RPC capabilities, wallet integration, transaction building,\n * or other features necessary for interacting with the Solana blockchain.\n *\n * Plugins are functions that take a client object as input and return a new client object\n * or a promise that resolves to a new client object. This allows for both synchronous\n * and asynchronous transformations and extensions of the client.\n *\n * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}\n * instance, which {@link createClient} provides as a starting point.\n *\n * @typeParam TInput - The input client object type that this plugin accepts.\n * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.\n *\n * @example Basic RPC plugin\n * Given an RPC endpoint, this plugin adds an `rpc` property to the client.\n *\n * ```ts\n * import { createClient, createSolanaRpc } from '@solana/kit';\n *\n * // Define a simple RPC plugin.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n *\n * // Use the plugin.\n * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));\n * await client.rpc.getLatestBlockhash().send();\n * ```\n *\n * @example Async plugin that generates a payer wallet\n * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.\n *\n * ```ts\n * import { createClient, generateKeypairSigner } from '@solana/kit';\n *\n * // Define a plugin that generates a new keypair signer.\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n *\n * // Use the plugin.\n * const client = await createClient().use(generatedPayerPlugin());\n * console.log(client.payer.address);\n * ```\n *\n * @example Plugins with input requirements\n * A plugin can specify required properties on the input client. The example below requires the\n * client to already have a `payer` signer attached to the client in order to perform an airdrop.\n *\n * ```ts\n * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';\n *\n * // Define a plugin that airdrops lamports to the payer set on the client.\n * function airdropPayerPlugin(lamports: Lamports) {\n * return async <T extends { payer: TransactionSigner }>(client: T) => {\n * await myAirdropFunction(client.payer, lamports);\n * return client;\n * };\n * }\n *\n * // Use the plugins.\n * const client = await createClient()\n * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.\n * .use(airdropPayerPlugin(lamports(1_000_000_000n)));\n * ```\n *\n * @example Chaining plugins\n * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.\n * The example below demonstrates how to gradually build a client with multiple plugins.\n * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.\n * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.\n *\n * ```ts\n * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';\n *\n * // Define multiple plugins.\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });\n * }\n * function rpcSubscriptionsPlugin(endpoint: string) {\n * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });\n * }\n * function generatedPayerPlugin() {\n * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });\n * }\n * function generatedAuthorityPlugin() {\n * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });\n * }\n *\n * // Chain plugins together.\n * const client = await createClient()\n * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))\n * .use(generatedPayerPlugin())\n * .use(generatedAuthorityPlugin());\n * ```\n */\nexport type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;\n\n/**\n * A client that can be extended with plugins.\n *\n * The `Client` type represents a client object that can be built up through\n * the application of one or more plugins. It provides a `use` method to\n * apply plugins, either synchronously (returning a new `Client`) or\n * asynchronously (returning an {@link AsyncClient}).\n *\n * @typeParam TSelf - The current shape of the client object including all applied plugins.\n */\nexport type Client<TSelf extends object> = TSelf & {\n /**\n * Applies a plugin to extend or transform the client.\n *\n * @param plugin The plugin function to apply to this client.\n * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;\n};\n\n/**\n * An asynchronous wrapper that represents a promise of a client.\n *\n * The `AsyncClient` type is returned when an async plugin is applied to a client.\n * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method\n * that allows chaining more plugins before the promise resolves.\n *\n * This enables fluent chaining of both synchronous and asynchronous plugins\n * without having to await intermediate promises.\n *\n * @typeParam TSelf - The shape of the client object that this async client will resolve to.\n */\nexport type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {\n /**\n * Applies a plugin to the client once it resolves.\n *\n * @param plugin The plugin function to apply to the resolved client.\n * @returns A new `AsyncClient` representing the result of applying the plugin.\n */\n readonly use: <TOutput extends Promise<object> | object>(\n plugin: ClientPlugin<TSelf, TOutput>,\n ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;\n};\n\n/** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */\nexport const createEmptyClient = () => createClient();\n\n/**\n * Creates a new empty client that can be extended with plugins.\n *\n * This serves as an entry point for building Solana clients.\n * Start with an empty client and chain the `.use()` method\n * to apply plugins that add various functionalities such as RPC\n * connectivity, wallet integration, transaction building, and more.\n *\n * See {@link ClientPlugin} for detailed examples on creating and using plugins.\n *\n * @returns An empty client object with only the `use` method available.\n *\n * @example Basic client setup\n * ```ts\n * import { createClient } from '@solana/client';\n * import { generatedPayer } from '@solana/kit-plugin-payer';\n * import { rpc } from '@solana/kit-plugin-rpc';\n *\n * const client = await createClient()\n * .use(generatedPayer())\n * .use(rpc('https://api.mainnet-beta.solana.com'));\n * ```\n */\nexport function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {\n return addUse(value ?? ({} as TSelf));\n}\n\nfunction addUse<TSelf extends object>(value: TSelf): Client<TSelf> {\n return Object.freeze(\n Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(value),\n use: {\n configurable: false,\n enumerable: true,\n value: function <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n const result = plugin(value);\n return result instanceof Promise ? createAsyncClient(result) : addUse(result);\n },\n writable: false,\n },\n },\n ),\n ) as Client<TSelf>;\n}\n\nfunction createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {\n return Object.freeze({\n catch(onrejected) {\n return promise.then(v => addUse(v)).catch(onrejected);\n },\n finally(onfinally) {\n return promise.then(v => addUse(v)).finally(onfinally);\n },\n then(onfulfilled, onrejected) {\n return promise.then(v => addUse(v)).then(onfulfilled, onrejected);\n },\n use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {\n return createAsyncClient(promise.then(plugin));\n },\n } as AsyncClient<TSelf>);\n}\n\n/**\n * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.\n *\n * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present\n * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed\n * as a single homomorphic mapped type so the inferred type displays as a flat object literal\n * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`\n * modifiers from both sides are preserved.\n *\n * Plugin authors who write their own merging helpers can reuse this type to keep the\n * inferred shape of their plugin's output legible in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the client being extended.\n * @typeParam TAdditions - The type of the properties being merged in.\n *\n * @example\n * ```ts\n * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {\n * return extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link extendClient}\n */\nexport type ExtendedClient<TClient extends object, TAdditions extends object> = {\n [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];\n} & {};\n\n/**\n * Extends a client object with additional properties, preserving property descriptors\n * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.\n *\n * Use this inside plugins instead of plain object spread (`{...client, ...additions}`)\n * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.\n * When the same key exists on both, `additions` wins.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single\n * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers\n * in editor tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @typeParam TAdditions - The type of the properties being added.\n * @param client - The original client object to extend.\n * @param additions - The properties to add or override on the client.\n * @returns A new object combining both, with `additions` taking precedence on conflicts.\n *\n * @example\n * ```ts\n * function rpcPlugin(endpoint: string) {\n * return <T extends object>(client: T) =>\n * extendClient(client, { rpc: createSolanaRpc(endpoint) });\n * }\n * ```\n *\n * @see {@link ClientPlugin}\n * @see {@link ExtendedClient}\n */\nexport function extendClient<TClient extends object, TAdditions extends object>(\n client: TClient,\n additions: TAdditions,\n): ExtendedClient<TClient, TAdditions> {\n const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as ExtendedClient<TClient, TAdditions>;\n}\n\nfunction toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {\n const result = {} as Record<string | symbol, PropertyDescriptor>;\n for (const key of Reflect.ownKeys(descriptors)) {\n result[key] = { ...descriptors[key as keyof T], configurable: true };\n }\n return result as T;\n}\n\n/**\n * Wraps a client with a cleanup function, making it {@link Disposable}.\n *\n * Plugin authors can use this to register teardown logic (e.g. closing\n * connections or clearing timers) that runs when the client is disposed.\n * If the client already implements `Symbol.dispose`, the existing dispose\n * logic is chained so that it runs after the new `cleanup` function.\n *\n * The return type is an {@link ExtendedClient}, which flattens the merged shape into a\n * single object literal so chained calls do not accumulate nested intersections in editor\n * tooltips and error messages.\n *\n * @typeParam TClient - The type of the original client.\n * @param client - The client to wrap.\n * @param cleanup - The cleanup function to run when the client is disposed.\n * @return A new client that extends `TClient` and implements `Disposable`.\n *\n * @example\n * Register a cleanup function in a plugin that opens a WebSocket connection.\n * ```ts\n * function myPlugin() {\n * return <T extends object>(client: T) => {\n * const socket = new WebSocket('wss://api.example.com');\n * return withCleanup(\n * extendClient(client, { socket }),\n * () => socket.close(),\n * );\n * };\n * }\n *\n * // Later, when the client is no longer needed:\n * using client = createClient().use(myPlugin();\n * // `socket.close()` is called automatically when `client` goes out of scope.\n * ```\n *\n * @see {@link extendClient}\n * @see {@link ExtendedClient}\n */\nexport function withCleanup<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n if (DISPOSABLE_STACK_PROPERTY in client) {\n return addCleanupToClientWithExistingStack(\n client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,\n cleanup,\n );\n } else {\n return addCleanupToClientWithoutExistingStack(client, cleanup);\n }\n}\n\nconst DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;\n\nfunction addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n // If we already have the stack, add the new cleanup to it\n client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);\n // We assume we already added a dispose method when we added the stack\n return client as unknown as ExtendedClient<TClient, Disposable>;\n}\n\nfunction addCleanupToClientWithoutExistingStack<TClient extends object>(\n client: TClient,\n cleanup: () => void,\n): ExtendedClient<TClient, Disposable> {\n const stack = new DisposableStack();\n\n // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack\n if (Symbol.dispose in client) {\n const existingDispose = (client as Disposable)[Symbol.dispose];\n stack.defer(() => existingDispose.call(client));\n }\n\n // Add the new cleanup to the stack\n stack.defer(cleanup);\n\n // We add our stack to the client, and replace any existing dispose method with our stack dispose\n const additions = {\n [DISPOSABLE_STACK_PROPERTY]: stack,\n [Symbol.dispose]() {\n stack[Symbol.dispose]();\n },\n };\n\n return extendClient(client, additions) as unknown as ExtendedClient<TClient, Disposable>;\n}\n"]}
@@ -165,6 +165,33 @@ export declare const createEmptyClient: () => Client<object>;
165
165
  * ```
166
166
  */
167
167
  export declare function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf>;
168
+ /**
169
+ * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.
170
+ *
171
+ * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present
172
+ * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed
173
+ * as a single homomorphic mapped type so the inferred type displays as a flat object literal
174
+ * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`
175
+ * modifiers from both sides are preserved.
176
+ *
177
+ * Plugin authors who write their own merging helpers can reuse this type to keep the
178
+ * inferred shape of their plugin's output legible in editor tooltips and error messages.
179
+ *
180
+ * @typeParam TClient - The type of the client being extended.
181
+ * @typeParam TAdditions - The type of the properties being merged in.
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {
186
+ * return extendClient(client, { rpc: createSolanaRpc(endpoint) });
187
+ * }
188
+ * ```
189
+ *
190
+ * @see {@link extendClient}
191
+ */
192
+ export type ExtendedClient<TClient extends object, TAdditions extends object> = {
193
+ [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];
194
+ } & {};
168
195
  /**
169
196
  * Extends a client object with additional properties, preserving property descriptors
170
197
  * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.
@@ -173,6 +200,10 @@ export declare function createClient<TSelf extends object = object>(value?: TSel
173
200
  * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.
174
201
  * When the same key exists on both, `additions` wins.
175
202
  *
203
+ * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single
204
+ * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers
205
+ * in editor tooltips and error messages.
206
+ *
176
207
  * @typeParam TClient - The type of the original client.
177
208
  * @typeParam TAdditions - The type of the properties being added.
178
209
  * @param client - The original client object to extend.
@@ -188,8 +219,9 @@ export declare function createClient<TSelf extends object = object>(value?: TSel
188
219
  * ```
189
220
  *
190
221
  * @see {@link ClientPlugin}
222
+ * @see {@link ExtendedClient}
191
223
  */
192
- export declare function extendClient<TClient extends object, TAdditions extends object>(client: TClient, additions: TAdditions): Omit<TClient, keyof TAdditions> & TAdditions;
224
+ export declare function extendClient<TClient extends object, TAdditions extends object>(client: TClient, additions: TAdditions): ExtendedClient<TClient, TAdditions>;
193
225
  /**
194
226
  * Wraps a client with a cleanup function, making it {@link Disposable}.
195
227
  *
@@ -198,6 +230,10 @@ export declare function extendClient<TClient extends object, TAdditions extends
198
230
  * If the client already implements `Symbol.dispose`, the existing dispose
199
231
  * logic is chained so that it runs after the new `cleanup` function.
200
232
  *
233
+ * The return type is an {@link ExtendedClient}, which flattens the merged shape into a
234
+ * single object literal so chained calls do not accumulate nested intersections in editor
235
+ * tooltips and error messages.
236
+ *
201
237
  * @typeParam TClient - The type of the original client.
202
238
  * @param client - The client to wrap.
203
239
  * @param cleanup - The cleanup function to run when the client is disposed.
@@ -222,6 +258,7 @@ export declare function extendClient<TClient extends object, TAdditions extends
222
258
  * ```
223
259
  *
224
260
  * @see {@link extendClient}
261
+ * @see {@link ExtendedClient}
225
262
  */
226
- export declare function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient;
263
+ export declare function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): ExtendedClient<TClient, Disposable>;
227
264
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGG;AACH,MAAM,MAAM,YAAY,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvH;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,CAAC,KAAK,SAAS,MAAM,IAAI,KAAK,GAAG;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,EACnD,MAAM,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,KACnC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;CACvG,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,KAAK,SAAS,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG;IACrE;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,EACnD,MAAM,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,KACnC,WAAW,CAAC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC;CACjG,CAAC;AAEF,sGAAsG;AACtG,eAAO,MAAM,iBAAiB,sBAAuB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAExF;AAuCD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,UAAU,SAAS,MAAM,EAC1E,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,UAAU,GACtB,IAAI,CAAC,OAAO,EAAE,MAAM,UAAU,CAAC,GAAG,UAAU,CAI9C;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,UAAU,GAAG,OAAO,CAS9G"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGG;AACH,MAAM,MAAM,YAAY,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvH;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,CAAC,KAAK,SAAS,MAAM,IAAI,KAAK,GAAG;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,EACnD,MAAM,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,KACnC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;CACvG,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,KAAK,SAAS,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG;IACrE;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,EACnD,MAAM,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,KACnC,WAAW,CAAC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC;CACjG,CAAC;AAEF,sGAAsG;AACtG,eAAO,MAAM,iBAAiB,sBAAuB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAExF;AAuCD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,MAAM,EAAE,UAAU,SAAS,MAAM,IAAI;KAC3E,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,UAAU,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,UAAU,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;CACjH,GAAG,EAAE,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,UAAU,SAAS,MAAM,EAC1E,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,UAAU,GACtB,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,CAIrC;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,EAC9C,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,IAAI,GACpB,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,CASrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/plugin-core",
3
- "version": "6.10.0-canary-20260514084615",
3
+ "version": "6.10.0",
4
4
  "description": "Core helpers for creating and extending Kit clients with plugins",
5
5
  "homepage": "https://www.solanakit.com/api#solanaplugin-core",
6
6
  "exports": {
package/src/client.ts CHANGED
@@ -213,6 +213,34 @@ function createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): Async
213
213
  } as AsyncClient<TSelf>);
214
214
  }
215
215
 
216
+ /**
217
+ * The result of extending a client of type `TClient` with additional properties of type `TAdditions`.
218
+ *
219
+ * Structurally equivalent to `Omit<TClient, keyof TAdditions> & TAdditions` — keys present
220
+ * on both `TClient` and `TAdditions` are replaced by the `TAdditions` version — but expressed
221
+ * as a single homomorphic mapped type so the inferred type displays as a flat object literal
222
+ * rather than a deeply nested chain of `Omit<...>` intersections. Optional (`?`) and `readonly`
223
+ * modifiers from both sides are preserved.
224
+ *
225
+ * Plugin authors who write their own merging helpers can reuse this type to keep the
226
+ * inferred shape of their plugin's output legible in editor tooltips and error messages.
227
+ *
228
+ * @typeParam TClient - The type of the client being extended.
229
+ * @typeParam TAdditions - The type of the properties being merged in.
230
+ *
231
+ * @example
232
+ * ```ts
233
+ * function withRpc<TClient extends object>(client: TClient, endpoint: string): ExtendedClient<TClient, { rpc: Rpc }> {
234
+ * return extendClient(client, { rpc: createSolanaRpc(endpoint) });
235
+ * }
236
+ * ```
237
+ *
238
+ * @see {@link extendClient}
239
+ */
240
+ export type ExtendedClient<TClient extends object, TAdditions extends object> = {
241
+ [K in keyof (Omit<TClient, keyof TAdditions> & TAdditions)]: (Omit<TClient, keyof TAdditions> & TAdditions)[K];
242
+ } & {};
243
+
216
244
  /**
217
245
  * Extends a client object with additional properties, preserving property descriptors
218
246
  * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.
@@ -221,6 +249,10 @@ function createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): Async
221
249
  * when the client may carry getters or symbol-keyed properties that spread would flatten or lose.
222
250
  * When the same key exists on both, `additions` wins.
223
251
  *
252
+ * The return type is an {@link ExtendedClient}, which flattens the merged shape into a single
253
+ * object literal so chained `extendClient` calls do not accumulate nested `Omit<...>` wrappers
254
+ * in editor tooltips and error messages.
255
+ *
224
256
  * @typeParam TClient - The type of the original client.
225
257
  * @typeParam TAdditions - The type of the properties being added.
226
258
  * @param client - The original client object to extend.
@@ -236,14 +268,15 @@ function createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): Async
236
268
  * ```
237
269
  *
238
270
  * @see {@link ClientPlugin}
271
+ * @see {@link ExtendedClient}
239
272
  */
240
273
  export function extendClient<TClient extends object, TAdditions extends object>(
241
274
  client: TClient,
242
275
  additions: TAdditions,
243
- ): Omit<TClient, keyof TAdditions> & TAdditions {
276
+ ): ExtendedClient<TClient, TAdditions> {
244
277
  const result = Object.defineProperties({}, toConfigurableDescriptors(Object.getOwnPropertyDescriptors(client)));
245
278
  Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));
246
- return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;
279
+ return Object.freeze(result) as ExtendedClient<TClient, TAdditions>;
247
280
  }
248
281
 
249
282
  function toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors: T): T {
@@ -262,6 +295,10 @@ function toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors:
262
295
  * If the client already implements `Symbol.dispose`, the existing dispose
263
296
  * logic is chained so that it runs after the new `cleanup` function.
264
297
  *
298
+ * The return type is an {@link ExtendedClient}, which flattens the merged shape into a
299
+ * single object literal so chained calls do not accumulate nested intersections in editor
300
+ * tooltips and error messages.
301
+ *
265
302
  * @typeParam TClient - The type of the original client.
266
303
  * @param client - The client to wrap.
267
304
  * @param cleanup - The cleanup function to run when the client is disposed.
@@ -286,8 +323,12 @@ function toConfigurableDescriptors<T extends PropertyDescriptorMap>(descriptors:
286
323
  * ```
287
324
  *
288
325
  * @see {@link extendClient}
326
+ * @see {@link ExtendedClient}
289
327
  */
290
- export function withCleanup<TClient extends object>(client: TClient, cleanup: () => void): Disposable & TClient {
328
+ export function withCleanup<TClient extends object>(
329
+ client: TClient,
330
+ cleanup: () => void,
331
+ ): ExtendedClient<TClient, Disposable> {
291
332
  if (DISPOSABLE_STACK_PROPERTY in client) {
292
333
  return addCleanupToClientWithExistingStack(
293
334
  client as Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack> & TClient,
@@ -303,17 +344,17 @@ const DISPOSABLE_STACK_PROPERTY = '__PRIVATE__DISPOSABLE_STACK' as const;
303
344
  function addCleanupToClientWithExistingStack<TClient extends Record<typeof DISPOSABLE_STACK_PROPERTY, DisposableStack>>(
304
345
  client: TClient,
305
346
  cleanup: () => void,
306
- ): Disposable & TClient {
347
+ ): ExtendedClient<TClient, Disposable> {
307
348
  // If we already have the stack, add the new cleanup to it
308
349
  client[DISPOSABLE_STACK_PROPERTY].defer(cleanup);
309
350
  // We assume we already added a dispose method when we added the stack
310
- return client as Disposable & TClient;
351
+ return client as unknown as ExtendedClient<TClient, Disposable>;
311
352
  }
312
353
 
313
354
  function addCleanupToClientWithoutExistingStack<TClient extends object>(
314
355
  client: TClient,
315
356
  cleanup: () => void,
316
- ): Disposable & TClient {
357
+ ): ExtendedClient<TClient, Disposable> {
317
358
  const stack = new DisposableStack();
318
359
 
319
360
  // If the client has an existing dispose method but not our stack, we maintain this existing cleanup by deferring it to the new stack
@@ -333,5 +374,5 @@ function addCleanupToClientWithoutExistingStack<TClient extends object>(
333
374
  },
334
375
  };
335
376
 
336
- return extendClient(client, additions) as unknown as Disposable & TClient;
377
+ return extendClient(client, additions) as unknown as ExtendedClient<TClient, Disposable>;
337
378
  }