@solana/plugin-core 6.3.1 → 6.3.2-canary-20260313112147

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/plugin-core",
3
- "version": "6.3.1",
3
+ "version": "6.3.2-canary-20260313112147",
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": {
@@ -33,7 +33,8 @@
33
33
  "types": "./dist/types/index.d.ts",
34
34
  "type": "commonjs",
35
35
  "files": [
36
- "./dist/"
36
+ "./dist/",
37
+ "./src/"
37
38
  ],
38
39
  "sideEffects": false,
39
40
  "keywords": [
package/src/client.ts ADDED
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Defines a plugin that transforms or extends a client with additional functionality.
3
+ *
4
+ * For instance, plugins may add RPC capabilities, wallet integration, transaction building,
5
+ * or other features necessary for interacting with the Solana blockchain.
6
+ *
7
+ * Plugins are functions that take a client object as input and return a new client object
8
+ * or a promise that resolves to a new client object. This allows for both synchronous
9
+ * and asynchronous transformations and extensions of the client.
10
+ *
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.
13
+ *
14
+ * @typeParam TInput - The input client object type that this plugin accepts.
15
+ * @typeParam TOutput - The output type. Either a new client object or a promise resolving to one.
16
+ *
17
+ * @example Basic RPC plugin
18
+ * Given an RPC endpoint, this plugin adds an `rpc` property to the client.
19
+ *
20
+ * ```ts
21
+ * import { createEmptyClient, createSolanaRpc } from '@solana/kit';
22
+ *
23
+ * // Define a simple RPC plugin.
24
+ * function rpcPlugin(endpoint: string) {
25
+ * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });
26
+ * }
27
+ *
28
+ * // Use the plugin.
29
+ * const client = createEmptyClient().use(rpcPlugin('https://api.mainnet-beta.solana.com'));
30
+ * await client.rpc.getLatestBlockhash().send();
31
+ * ```
32
+ *
33
+ * @example Async plugin that generates a payer wallet
34
+ * The following plugin shows how to create an asynchronous plugin that generates a new keypair signer.
35
+ *
36
+ * ```ts
37
+ * import { createEmptyClient, generateKeypairSigner } from '@solana/kit';
38
+ *
39
+ * // Define a plugin that generates a new keypair signer.
40
+ * function generatedPayerPlugin() {
41
+ * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });
42
+ * }
43
+ *
44
+ * // Use the plugin.
45
+ * const client = await createEmptyClient().use(generatedPayerPlugin());
46
+ * console.log(client.payer.address);
47
+ * ```
48
+ *
49
+ * @example Plugins with input requirements
50
+ * A plugin can specify required properties on the input client. The example below requires the
51
+ * client to already have a `payer` signer attached to the client in order to perform an airdrop.
52
+ *
53
+ * ```ts
54
+ * import { createEmptyClient, TransactionSigner, Lamports, lamports } from '@solana/kit';
55
+ *
56
+ * // Define a plugin that airdrops lamports to the payer set on the client.
57
+ * function airdropPayerPlugin(lamports: Lamports) {
58
+ * return async <T extends { payer: TransactionSigner }>(client: T) => {
59
+ * await myAirdropFunction(client.payer, lamports);
60
+ * return client;
61
+ * };
62
+ * }
63
+ *
64
+ * // Use the plugins.
65
+ * const client = await createEmptyClient()
66
+ * .use(generatedPayerPlugin()) // This is required before using the airdrop plugin.
67
+ * .use(airdropPayerPlugin(lamports(1_000_000_000n)));
68
+ * ```
69
+ *
70
+ * @example Chaining plugins
71
+ * Multiple plugins — asynchronous or not — can be chained together to build up complex clients.
72
+ * The example below demonstrates how to gradually build a client with multiple plugins.
73
+ * Notice how, despite having multiple asynchronous plugins, we only need to `await` the final result.
74
+ * This is because the `use` method on `AsyncClient` returns another `AsyncClient`, allowing for seamless chaining.
75
+ *
76
+ * ```ts
77
+ * import { createEmptyClient, createSolanaRpc, createSolanaRpcSubscriptions, generateKeypairSigner } from '@solana/kit';
78
+ *
79
+ * // Define multiple plugins.
80
+ * function rpcPlugin(endpoint: string) {
81
+ * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpc(endpoint) });
82
+ * }
83
+ * function rpcSubscriptionsPlugin(endpoint: string) {
84
+ * return <T extends object>(client: T) => ({...client, rpc: createSolanaRpcSubscriptions(endpoint) });
85
+ * }
86
+ * function generatedPayerPlugin() {
87
+ * return async <T extends object>(client: T) => ({...client, payer: await generateKeypairSigner() });
88
+ * }
89
+ * function generatedAuthorityPlugin() {
90
+ * return async <T extends object>(client: T) => ({...client, authority: await generateKeypairSigner() });
91
+ * }
92
+ *
93
+ * // Chain plugins together.
94
+ * const client = await createEmptyClient()
95
+ * .use(rpcPlugin('https://api.mainnet-beta.solana.com'))
96
+ * .use(rpcSubscriptionsPlugin('wss://api.mainnet-beta.solana.com'))
97
+ * .use(generatedPayerPlugin())
98
+ * .use(generatedAuthorityPlugin());
99
+ * ```
100
+ */
101
+ export type ClientPlugin<TInput extends object, TOutput extends Promise<object> | object> = (input: TInput) => TOutput;
102
+
103
+ /**
104
+ * A client that can be extended with plugins.
105
+ *
106
+ * The `Client` type represents a client object that can be built up through
107
+ * the application of one or more plugins. It provides a `use` method to
108
+ * apply plugins, either synchronously (returning a new `Client`) or
109
+ * asynchronously (returning an {@link AsyncClient}).
110
+ *
111
+ * @typeParam TSelf - The current shape of the client object including all applied plugins.
112
+ */
113
+ export type Client<TSelf extends object> = TSelf & {
114
+ /**
115
+ * Applies a plugin to extend or transform the client.
116
+ *
117
+ * @param plugin The plugin function to apply to this client.
118
+ * @returns Either a new `Client` (for sync plugins) or {@link AsyncClient} (for async plugins).
119
+ */
120
+ readonly use: <TOutput extends Promise<object> | object>(
121
+ plugin: ClientPlugin<TSelf, TOutput>,
122
+ ) => TOutput extends Promise<infer U> ? AsyncClient<U extends object ? U : never> : Client<TOutput>;
123
+ };
124
+
125
+ /**
126
+ * An asynchronous wrapper that represents a promise of a client.
127
+ *
128
+ * The `AsyncClient` type is returned when an async plugin is applied to a client.
129
+ * It behaves like a `Promise<Client<TSelf>>` but with an additional `use` method
130
+ * that allows chaining more plugins before the promise resolves.
131
+ *
132
+ * This enables fluent chaining of both synchronous and asynchronous plugins
133
+ * without having to await intermediate promises.
134
+ *
135
+ * @typeParam TSelf - The shape of the client object that this async client will resolve to.
136
+ */
137
+ export type AsyncClient<TSelf extends object> = Promise<Client<TSelf>> & {
138
+ /**
139
+ * Applies a plugin to the client once it resolves.
140
+ *
141
+ * @param plugin The plugin function to apply to the resolved client.
142
+ * @returns A new `AsyncClient` representing the result of applying the plugin.
143
+ */
144
+ readonly use: <TOutput extends Promise<object> | object>(
145
+ plugin: ClientPlugin<TSelf, TOutput>,
146
+ ) => AsyncClient<TOutput extends Promise<infer U> ? (U extends object ? U : never) : TOutput>;
147
+ };
148
+
149
+ // TODO(loris): Add examples in this docblock using real plugins once they have been published.
150
+
151
+ /**
152
+ * Creates a new empty client that can be extended with plugins.
153
+ *
154
+ * This serves as an entry point for building Solana clients.
155
+ * Start with an empty client and chain the `.use()` method
156
+ * to apply plugins that add various functionalities such as RPC
157
+ * connectivity, wallet integration, transaction building, and more.
158
+ *
159
+ * See {@link ClientPlugin} for detailed examples on creating and using plugins.
160
+ *
161
+ * @returns An empty client object with only the `use` method available.
162
+ *
163
+ * @example Basic client setup
164
+ * ```ts
165
+ * import { createEmptyClient } from '@solana/client';
166
+ *
167
+ * const client = createEmptyClient()
168
+ * .use(myRpcPlugin('https://api.mainnet-beta.solana.com'))
169
+ * .use(myWalletPlugin());
170
+ * ```
171
+ */
172
+ export function createEmptyClient(): Client<object> {
173
+ return addUse({});
174
+ }
175
+
176
+ function addUse<TSelf extends object>(value: TSelf): Client<TSelf> {
177
+ return Object.freeze({
178
+ ...value,
179
+ use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {
180
+ const result = plugin(value);
181
+ return result instanceof Promise ? createAsyncClient(result) : addUse(result);
182
+ },
183
+ } as Client<TSelf>);
184
+ }
185
+
186
+ function createAsyncClient<TSelf extends object>(promise: Promise<TSelf>): AsyncClient<TSelf> {
187
+ return Object.freeze({
188
+ catch(onrejected) {
189
+ return promise.then(v => addUse(v)).catch(onrejected);
190
+ },
191
+ finally(onfinally) {
192
+ return promise.then(v => addUse(v)).finally(onfinally);
193
+ },
194
+ then(onfulfilled, onrejected) {
195
+ return promise.then(v => addUse(v)).then(onfulfilled, onrejected);
196
+ },
197
+ use<TOutput extends Promise<object> | object>(plugin: ClientPlugin<TSelf, TOutput>) {
198
+ return createAsyncClient(promise.then(plugin));
199
+ },
200
+ } as AsyncClient<TSelf>);
201
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This package contains utilities for creating modular Kit clients that can be extended
3
+ * with plugins. It can be used standalone, but it is also exported as part of Kit
4
+ * [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export * from './client';