@solana/plugin-core 6.6.0 → 6.7.0-canary-20260402094946

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,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  // src/client.ts
4
- function createEmptyClient() {
5
- return addUse({});
4
+ var createEmptyClient = () => createClient();
5
+ function createClient(value) {
6
+ return addUse(value ?? {});
6
7
  }
7
8
  function addUse(value) {
8
9
  return Object.freeze(
@@ -75,6 +76,7 @@ function addCleanupToClientWithoutExistingStack(client, cleanup) {
75
76
  return extendClient(client, additions);
76
77
  }
77
78
 
79
+ exports.createClient = createClient;
78
80
  exports.createEmptyClient = createEmptyClient;
79
81
  exports.extendClient = extendClient;
80
82
  exports.withCleanup = withCleanup;
@@ -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 createEmptyClient} 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 { createEmptyClient, 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 = createEmptyClient().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 { createEmptyClient, 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 createEmptyClient().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 { createEmptyClient, 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 createEmptyClient()\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 { createEmptyClient, 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 createEmptyClient()\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// TODO(loris): Add examples in this docblock using real plugins once they have been published.\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 { createEmptyClient } from '@solana/client';\n *\n * const client = createEmptyClient()\n * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(myWalletPlugin());\n * ```\n */\nexport function createEmptyClient(): Client<object> {\n return addUse({});\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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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 = createEmptyClient().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.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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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,6 +1,7 @@
1
1
  // src/client.ts
2
- function createEmptyClient() {
3
- return addUse({});
2
+ var createEmptyClient = () => createClient();
3
+ function createClient(value) {
4
+ return addUse(value ?? {});
4
5
  }
5
6
  function addUse(value) {
6
7
  return Object.freeze(
@@ -73,6 +74,6 @@ function addCleanupToClientWithoutExistingStack(client, cleanup) {
73
74
  return extendClient(client, additions);
74
75
  }
75
76
 
76
- export { createEmptyClient, extendClient, withCleanup };
77
+ export { createClient, createEmptyClient, extendClient, withCleanup };
77
78
  //# sourceMappingURL=index.browser.mjs.map
78
79
  //# sourceMappingURL=index.browser.mjs.map
@@ -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 createEmptyClient} 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 { createEmptyClient, 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 = createEmptyClient().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 { createEmptyClient, 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 createEmptyClient().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 { createEmptyClient, 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 createEmptyClient()\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 { createEmptyClient, 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 createEmptyClient()\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// TODO(loris): Add examples in this docblock using real plugins once they have been published.\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 { createEmptyClient } from '@solana/client';\n *\n * const client = createEmptyClient()\n * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(myWalletPlugin());\n * ```\n */\nexport function createEmptyClient(): Client<object> {\n return addUse({});\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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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 = createEmptyClient().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 * 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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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,6 +1,7 @@
1
1
  // src/client.ts
2
- function createEmptyClient() {
3
- return addUse({});
2
+ var createEmptyClient = () => createClient();
3
+ function createClient(value) {
4
+ return addUse(value ?? {});
4
5
  }
5
6
  function addUse(value) {
6
7
  return Object.freeze(
@@ -73,6 +74,6 @@ function addCleanupToClientWithoutExistingStack(client, cleanup) {
73
74
  return extendClient(client, additions);
74
75
  }
75
76
 
76
- export { createEmptyClient, extendClient, withCleanup };
77
+ export { createClient, createEmptyClient, extendClient, withCleanup };
77
78
  //# sourceMappingURL=index.native.mjs.map
78
79
  //# sourceMappingURL=index.native.mjs.map
@@ -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 createEmptyClient} 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 { createEmptyClient, 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 = createEmptyClient().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 { createEmptyClient, 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 createEmptyClient().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 { createEmptyClient, 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 createEmptyClient()\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 { createEmptyClient, 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 createEmptyClient()\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// TODO(loris): Add examples in this docblock using real plugins once they have been published.\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 { createEmptyClient } from '@solana/client';\n *\n * const client = createEmptyClient()\n * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(myWalletPlugin());\n * ```\n */\nexport function createEmptyClient(): Client<object> {\n return addUse({});\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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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 = createEmptyClient().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;AA0BO,SAAS,YAAA,CACZ,QACA,SAAA,EAC4C;AAC5C,EAAA,MAAM,MAAA,GAAS,OAAO,gBAAA,CAAiB,IAAI,MAAA,CAAO,yBAAA,CAA0B,MAAM,CAAC,CAAA;AACnF,EAAA,MAAA,CAAO,gBAAA,CAAiB,MAAA,EAAQ,MAAA,CAAO,yBAAA,CAA0B,SAAS,CAAC,CAAA;AAC3E,EAAA,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAC/B;AAmCO,SAAS,WAAA,CAAoC,QAAiB,OAAA,EAA2C;AAC5G,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,EACoB;AAEpB,EAAA,MAAA,CAAO,yBAAyB,CAAA,CAAE,KAAA,CAAM,OAAO,CAAA;AAE/C,EAAA,OAAO,MAAA;AACX;AAEA,SAAS,sCAAA,CACL,QACA,OAAA,EACoB;AACpB,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.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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  // src/client.ts
4
- function createEmptyClient() {
5
- return addUse({});
4
+ var createEmptyClient = () => createClient();
5
+ function createClient(value) {
6
+ return addUse(value ?? {});
6
7
  }
7
8
  function addUse(value) {
8
9
  return Object.freeze(
@@ -75,6 +76,7 @@ function addCleanupToClientWithoutExistingStack(client, cleanup) {
75
76
  return extendClient(client, additions);
76
77
  }
77
78
 
79
+ exports.createClient = createClient;
78
80
  exports.createEmptyClient = createEmptyClient;
79
81
  exports.extendClient = extendClient;
80
82
  exports.withCleanup = withCleanup;
@@ -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 createEmptyClient} 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 { createEmptyClient, 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 = createEmptyClient().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 { createEmptyClient, 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 createEmptyClient().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 { createEmptyClient, 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 createEmptyClient()\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 { createEmptyClient, 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 createEmptyClient()\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// TODO(loris): Add examples in this docblock using real plugins once they have been published.\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 { createEmptyClient } from '@solana/client';\n *\n * const client = createEmptyClient()\n * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(myWalletPlugin());\n * ```\n */\nexport function createEmptyClient(): Client<object> {\n return addUse({});\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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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 = createEmptyClient().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.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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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,6 +1,7 @@
1
1
  // src/client.ts
2
- function createEmptyClient() {
3
- return addUse({});
2
+ var createEmptyClient = () => createClient();
3
+ function createClient(value) {
4
+ return addUse(value ?? {});
4
5
  }
5
6
  function addUse(value) {
6
7
  return Object.freeze(
@@ -73,6 +74,6 @@ function addCleanupToClientWithoutExistingStack(client, cleanup) {
73
74
  return extendClient(client, additions);
74
75
  }
75
76
 
76
- export { createEmptyClient, extendClient, withCleanup };
77
+ export { createClient, createEmptyClient, extendClient, withCleanup };
77
78
  //# sourceMappingURL=index.node.mjs.map
78
79
  //# sourceMappingURL=index.node.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";AA2KO,SAAS,iBAAA,GAAoC;AAChD,EAAA,OAAO,MAAA,CAAO,EAAE,CAAA;AACpB;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;AA0BO,SAAS,YAAA,CACZ,QACA,SAAA,EAC4C;AAC5C,EAAA,MAAM,MAAA,GAAS,OAAO,gBAAA,CAAiB,IAAI,MAAA,CAAO,yBAAA,CAA0B,MAAM,CAAC,CAAA;AACnF,EAAA,MAAA,CAAO,gBAAA,CAAiB,MAAA,EAAQ,MAAA,CAAO,yBAAA,CAA0B,SAAS,CAAC,CAAA;AAC3E,EAAA,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAC/B;AAmCO,SAAS,WAAA,CAAoC,QAAiB,OAAA,EAA2C;AAC5G,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,EACoB;AAEpB,EAAA,MAAA,CAAO,yBAAyB,CAAA,CAAE,KAAA,CAAM,OAAO,CAAA;AAE/C,EAAA,OAAO,MAAA;AACX;AAEA,SAAS,sCAAA,CACL,QACA,OAAA,EACoB;AACpB,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.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 createEmptyClient} 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 { createEmptyClient, 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 = createEmptyClient().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 { createEmptyClient, 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 createEmptyClient().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 { createEmptyClient, 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 createEmptyClient()\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 { createEmptyClient, 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 createEmptyClient()\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// TODO(loris): Add examples in this docblock using real plugins once they have been published.\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 { createEmptyClient } from '@solana/client';\n *\n * const client = createEmptyClient()\n * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))\n * .use(myWalletPlugin());\n * ```\n */\nexport function createEmptyClient(): Client<object> {\n return addUse({});\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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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 = createEmptyClient().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 * 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({}, Object.getOwnPropertyDescriptors(client));\n Object.defineProperties(result, Object.getOwnPropertyDescriptors(additions));\n return Object.freeze(result) as Omit<TClient, keyof TAdditions> & TAdditions;\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"]}
@@ -9,7 +9,7 @@
9
9
  * and asynchronous transformations and extensions of the client.
10
10
  *
11
11
  * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}
12
- * instance, which {@link createEmptyClient} provides as a starting point.
12
+ * instance, which {@link createClient} provides as a starting point.
13
13
  *
14
14
  * @typeParam TInput - The input client object type that this plugin accepts.
15
15
  * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.
@@ -18,7 +18,7 @@
18
18
  * Given an RPC endpoint, this plugin adds an `rpc` property to the client.
19
19
  *
20
20
  * ```ts
21
- * import { createEmptyClient, createSolanaRpc } from '@solana/kit';
21
+ * import { createClient, createSolanaRpc } from '@solana/kit';
22
22
  *
23
23
  * // Define a simple RPC plugin.
24
24
  * function rpcPlugin(endpoint: string) {
@@ -26,7 +26,7 @@
26
26
  * }
27
27
  *
28
28
  * // Use the plugin.
29
- * const client = createEmptyClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));
29
+ * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));
30
30
  * await client.rpc.getLatestBlockhash().send();
31
31
  * ```
32
32
  *
@@ -34,7 +34,7 @@
34
34
  * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.
35
35
  *
36
36
  * ```ts
37
- * import { createEmptyClient, generateKeypairSigner } from '@solana/kit';
37
+ * import { createClient, generateKeypairSigner } from '@solana/kit';
38
38
  *
39
39
  * // Define a plugin that generates a new keypair signer.
40
40
  * function generatedPayerPlugin() {
@@ -42,7 +42,7 @@
42
42
  * }
43
43
  *
44
44
  * // Use the plugin.
45
- * const client = await createEmptyClient().use(generatedPayerPlugin());
45
+ * const client = await createClient().use(generatedPayerPlugin());
46
46
  * console.log(client.payer.address);
47
47
  * ```
48
48
  *
@@ -51,7 +51,7 @@
51
51
  * client to already have a `payer` signer attached to the client in order to perform an airdrop.
52
52
  *
53
53
  * ```ts
54
- * import { createEmptyClient, TransactionSigner, Lamports, lamports } from '@solana/kit';
54
+ * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';
55
55
  *
56
56
  * // Define a plugin that airdrops lamports to the payer set on the client.
57
57
  * function airdropPayerPlugin(lamports: Lamports) {
@@ -62,7 +62,7 @@
62
62
  * }
63
63
  *
64
64
  * // Use the plugins.
65
- * const client = await createEmptyClient()
65
+ * const client = await createClient()
66
66
  * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.
67
67
  * .use(airdropPayerPlugin(lamports(1_000_000_000n)));
68
68
  * ```
@@ -74,7 +74,7 @@
74
74
  * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.
75
75
  *
76
76
  * ```ts
77
- * import { createEmptyClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';
77
+ * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';
78
78
  *
79
79
  * // Define multiple plugins.
80
80
  * function rpcPlugin(endpoint: string) {
@@ -91,7 +91,7 @@
91
91
  * }
92
92
  *
93
93
  * // Chain plugins together.
94
- * const client = await createEmptyClient()
94
+ * const client = await createClient()
95
95
  * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))
96
96
  * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))
97
97
  * .use(generatedPayerPlugin())
@@ -139,6 +139,8 @@ export type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {
139
139
  */
140
140
  readonly use: <TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;
141
141
  };
142
+ /** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */
143
+ export declare const createEmptyClient: () => Client<object>;
142
144
  /**
143
145
  * Creates a new empty client that can be extended with plugins.
144
146
  *
@@ -153,14 +155,16 @@ export type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {
153
155
  *
154
156
  * @example Basic client setup
155
157
  * ```ts
156
- * import { createEmptyClient } from '@solana/client';
158
+ * import { createClient } from '@solana/client';
159
+ * import { generatedPayer } from '@solana/kit-plugin-payer';
160
+ * import { rpc } from '@solana/kit-plugin-rpc';
157
161
  *
158
- * const client = createEmptyClient()
159
- * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))
160
- * .use(myWalletPlugin());
162
+ * const client = await createClient()
163
+ * .use(generatedPayer())
164
+ * .use(rpc('https://api.mainnet-beta.solana.com'));
161
165
  * ```
162
166
  */
163
- export declare function createEmptyClient(): Client<object>;
167
+ export declare function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf>;
164
168
  /**
165
169
  * Extends a client object with additional properties, preserving property descriptors
166
170
  * (getters, symbol-keyed properties, and non-enumerable properties) from both objects.
@@ -213,7 +217,7 @@ export declare function extendClient<TClient extends object, TAdditions extends
213
217
  * }
214
218
  *
215
219
  * // Later, when the client is no longer needed:
216
- * using client = createEmptyClient().use(myPlugin();
220
+ * using client = createClient().use(myPlugin();
217
221
  * // `socket.close()` is called automatically when `client` goes out of scope.
218
222
  * ```
219
223
  *
@@ -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;AAIF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,CAAC,CAElD;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;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,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;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,UAAU,GAAG,OAAO,CAS9G"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/plugin-core",
3
- "version": "6.6.0",
3
+ "version": "6.7.0-canary-20260402094946",
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
@@ -9,7 +9,7 @@
9
9
  * and asynchronous transformations and extensions of the client.
10
10
  *
11
11
  * Plugins are usually applied using the `use` method on a {@link Client} or {@link AsyncClient}
12
- * instance, which {@link createEmptyClient} provides as a starting point.
12
+ * instance, which {@link createClient} provides as a starting point.
13
13
  *
14
14
  * @typeParam TInput - The input client object type that this plugin accepts.
15
15
  * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.
@@ -18,7 +18,7 @@
18
18
  * Given an RPC endpoint, this plugin adds an `rpc` property to the client.
19
19
  *
20
20
  * ```ts
21
- * import { createEmptyClient, createSolanaRpc } from '@solana/kit';
21
+ * import { createClient, createSolanaRpc } from '@solana/kit';
22
22
  *
23
23
  * // Define a simple RPC plugin.
24
24
  * function rpcPlugin(endpoint: string) {
@@ -26,7 +26,7 @@
26
26
  * }
27
27
  *
28
28
  * // Use the plugin.
29
- * const client = createEmptyClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));
29
+ * const client = createClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));
30
30
  * await client.rpc.getLatestBlockhash().send();
31
31
  * ```
32
32
  *
@@ -34,7 +34,7 @@
34
34
  * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.
35
35
  *
36
36
  * ```ts
37
- * import { createEmptyClient, generateKeypairSigner } from '@solana/kit';
37
+ * import { createClient, generateKeypairSigner } from '@solana/kit';
38
38
  *
39
39
  * // Define a plugin that generates a new keypair signer.
40
40
  * function generatedPayerPlugin() {
@@ -42,7 +42,7 @@
42
42
  * }
43
43
  *
44
44
  * // Use the plugin.
45
- * const client = await createEmptyClient().use(generatedPayerPlugin());
45
+ * const client = await createClient().use(generatedPayerPlugin());
46
46
  * console.log(client.payer.address);
47
47
  * ```
48
48
  *
@@ -51,7 +51,7 @@
51
51
  * client to already have a `payer` signer attached to the client in order to perform an airdrop.
52
52
  *
53
53
  * ```ts
54
- * import { createEmptyClient, TransactionSigner, Lamports, lamports } from '@solana/kit';
54
+ * import { createClient, TransactionSigner, Lamports, lamports } from '@solana/kit';
55
55
  *
56
56
  * // Define a plugin that airdrops lamports to the payer set on the client.
57
57
  * function airdropPayerPlugin(lamports: Lamports) {
@@ -62,7 +62,7 @@
62
62
  * }
63
63
  *
64
64
  * // Use the plugins.
65
- * const client = await createEmptyClient()
65
+ * const client = await createClient()
66
66
  * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.
67
67
  * .use(airdropPayerPlugin(lamports(1_000_000_000n)));
68
68
  * ```
@@ -74,7 +74,7 @@
74
74
  * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.
75
75
  *
76
76
  * ```ts
77
- * import { createEmptyClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';
77
+ * import { createClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';
78
78
  *
79
79
  * // Define multiple plugins.
80
80
  * function rpcPlugin(endpoint: string) {
@@ -91,7 +91,7 @@
91
91
  * }
92
92
  *
93
93
  * // Chain plugins together.
94
- * const client = await createEmptyClient()
94
+ * const client = await createClient()
95
95
  * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))
96
96
  * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))
97
97
  * .use(generatedPayerPlugin())
@@ -146,7 +146,8 @@ export type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {
146
146
  ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;
147
147
  };
148
148
 
149
- // TODO(loris): Add examples in this docblock using real plugins once they have been published.
149
+ /** @deprecated This function has been renamed. Use `createClient` instead. It behaves identically. */
150
+ export const createEmptyClient = () => createClient();
150
151
 
151
152
  /**
152
153
  * Creates a new empty client that can be extended with plugins.
@@ -162,15 +163,17 @@ export type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {
162
163
  *
163
164
  * @example Basic client setup
164
165
  * ```ts
165
- * import { createEmptyClient } from '@solana/client';
166
+ * import { createClient } from '@solana/client';
167
+ * import { generatedPayer } from '@solana/kit-plugin-payer';
168
+ * import { rpc } from '@solana/kit-plugin-rpc';
166
169
  *
167
- * const client = createEmptyClient()
168
- * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))
169
- * .use(myWalletPlugin());
170
+ * const client = await createClient()
171
+ * .use(generatedPayer())
172
+ * .use(rpc('https://api.mainnet-beta.solana.com'));
170
173
  * ```
171
174
  */
172
- export function createEmptyClient(): Client<object> {
173
- return addUse({});
175
+ export function createClient<TSelf extends object = object>(value?: TSelf): Client<TSelf> {
176
+ return addUse(value ?? ({} as TSelf));
174
177
  }
175
178
 
176
179
  function addUse<TSelf extends object>(value: TSelf): Client<TSelf> {
@@ -270,7 +273,7 @@ export function extendClient<TClient extends object, TAdditions extends object>(
270
273
  * }
271
274
  *
272
275
  * // Later, when the client is no longer needed:
273
- * using client = createEmptyClient().use(myPlugin();
276
+ * using client = createClient().use(myPlugin();
274
277
  * // `socket.close()` is called automatically when `client` goes out of scope.
275
278
  * ```
276
279
  *