@solana/kora 0.2.1 → 0.3.0-beta.2

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.
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Stable numeric error codes for RPC responses following JSON-RPC 2.0 spec (-32000 to -32099 for server errors).
3
+ */
4
+ export var KoraErrorCode;
5
+ (function (KoraErrorCode) {
6
+ // Validation errors (-32000 to -32019)
7
+ KoraErrorCode[KoraErrorCode["InvalidTransaction"] = -32000] = "InvalidTransaction";
8
+ KoraErrorCode[KoraErrorCode["ValidationError"] = -32001] = "ValidationError";
9
+ KoraErrorCode[KoraErrorCode["UnsupportedFeeToken"] = -32002] = "UnsupportedFeeToken";
10
+ KoraErrorCode[KoraErrorCode["InsufficientFunds"] = -32003] = "InsufficientFunds";
11
+ KoraErrorCode[KoraErrorCode["InvalidRequest"] = -32004] = "InvalidRequest";
12
+ KoraErrorCode[KoraErrorCode["FeeEstimationFailed"] = -32005] = "FeeEstimationFailed";
13
+ KoraErrorCode[KoraErrorCode["TransactionExecutionFailed"] = -32006] = "TransactionExecutionFailed";
14
+ // Signing errors (-32020 to -32029)
15
+ KoraErrorCode[KoraErrorCode["SigningError"] = -32020] = "SigningError";
16
+ // Auth / Rate limiting (-32030 to -32039)
17
+ KoraErrorCode[KoraErrorCode["RateLimitExceeded"] = -32030] = "RateLimitExceeded";
18
+ KoraErrorCode[KoraErrorCode["UsageLimitExceeded"] = -32031] = "UsageLimitExceeded";
19
+ KoraErrorCode[KoraErrorCode["Unauthorized"] = -32032] = "Unauthorized";
20
+ // Token / Swap (-32040 to -32049)
21
+ KoraErrorCode[KoraErrorCode["SwapError"] = -32040] = "SwapError";
22
+ KoraErrorCode[KoraErrorCode["TokenOperationError"] = -32041] = "TokenOperationError";
23
+ // Account errors (-32050 to -32059)
24
+ KoraErrorCode[KoraErrorCode["AccountNotFound"] = -32050] = "AccountNotFound";
25
+ // External services (-32060 to -32069)
26
+ KoraErrorCode[KoraErrorCode["JitoError"] = -32060] = "JitoError";
27
+ KoraErrorCode[KoraErrorCode["RecaptchaError"] = -32061] = "RecaptchaError";
28
+ // Internal errors (-32090 to -32099)
29
+ KoraErrorCode[KoraErrorCode["InternalServerError"] = -32090] = "InternalServerError";
30
+ KoraErrorCode[KoraErrorCode["ConfigError"] = -32091] = "ConfigError";
31
+ KoraErrorCode[KoraErrorCode["SerializationError"] = -32092] = "SerializationError";
32
+ KoraErrorCode[KoraErrorCode["RpcError"] = -32093] = "RpcError";
33
+ })(KoraErrorCode || (KoraErrorCode = {}));
34
+ /**
35
+ * Represents a structured error returned by the Kora paymaster service.
36
+ */
37
+ export class KoraError extends Error {
38
+ /** The stable numeric error code */
39
+ code;
40
+ /** Optional structured data about the error */
41
+ data;
42
+ constructor(code, message, data) {
43
+ const finalCode = code ?? -32603;
44
+ const finalMessage = message ?? 'Unknown error';
45
+ super(`Kora Error ${finalCode}: ${finalMessage}`);
46
+ this.name = 'KoraError';
47
+ this.code = finalCode;
48
+ this.data = data;
49
+ // Ensure proper stack trace in environments that support Error.captureStackTrace
50
+ if (Error.captureStackTrace) {
51
+ Error.captureStackTrace(this, KoraError);
52
+ }
53
+ }
54
+ }
@@ -1,4 +1,4 @@
1
+ export * from './error.js';
1
2
  export * from './types/index.js';
2
3
  export { KoraClient } from './client.js';
3
- export { koraPlugin, type KoraPlugin } from './kit/plugin.js';
4
- export { createKitKoraClient, type KoraKitClient } from './kit/index.js';
4
+ export { koraPlugin, type KoraApi } from './plugin.js';
package/dist/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
+ export * from './error.js';
1
2
  export * from './types/index.js';
2
3
  export { KoraClient } from './client.js';
3
- export { koraPlugin } from './kit/plugin.js';
4
- export { createKitKoraClient } from './kit/index.js';
4
+ export { koraPlugin } from './plugin.js';
@@ -1,7 +1,7 @@
1
1
  import { type Address, type TransactionMessage, type TransactionMessageWithFeePayer, type TransactionSigner } from '@solana/kit';
2
2
  import { KoraClient } from '../client.js';
3
- import type { KoraKitClientConfig } from '../types/index.js';
4
- export declare function createKoraTransactionPlanExecutor(koraClient: KoraClient, config: KoraKitClientConfig, payerSigner: TransactionSigner, payment: {
3
+ import type { KoraBundleConfig } from '../types/index.js';
4
+ export declare function createKoraTransactionPlanExecutor(koraClient: KoraClient, config: KoraBundleConfig, userSigner: TransactionSigner, payerSigner: TransactionSigner, payment: {
5
5
  destinationTokenAccount: Address;
6
6
  sourceTokenAccount: Address;
7
7
  } | undefined, resolveProvisoryComputeUnitLimit: (<T extends TransactionMessage & TransactionMessageWithFeePayer>(transactionMessage: T) => Promise<T>) | undefined): import("@solana/kit").TransactionPlanExecutor<import("@solana/kit").TransactionPlanResultContext>;
@@ -1,6 +1,11 @@
1
1
  import { appendTransactionMessageInstructions, blockhash, createTransactionMessage, createTransactionPlanExecutor, getBase64EncodedWireTransaction, getBase64Encoder, getSignatureFromTransaction, getTransactionDecoder, partiallySignTransactionMessageWithSigners, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signature, } from '@solana/kit';
2
2
  import { removePaymentInstruction, updatePaymentInstructionAmount } from './payment.js';
3
- export function createKoraTransactionPlanExecutor(koraClient, config, payerSigner, payment, resolveProvisoryComputeUnitLimit) {
3
+ // TODO: Create a bundle-aware executor (e.g. `createKoraBundlePlanExecutor`) that collects
4
+ // multiple planned transaction messages into a single `signAndSendBundle` call instead of
5
+ // submitting each one individually via `signAndSendTransaction`. This would let users
6
+ // compose Jito bundles through the Kit plan/execute pipeline rather than manually encoding
7
+ // transactions and calling `client.kora.signAndSendBundle()`.
8
+ export function createKoraTransactionPlanExecutor(koraClient, config, userSigner, payerSigner, payment, resolveProvisoryComputeUnitLimit) {
4
9
  return createTransactionPlanExecutor({
5
10
  async executeTransactionMessage(_context, transactionMessage) {
6
11
  // Kora manages blockhash validity; set max height to avoid premature client-side expiry checks
@@ -20,8 +25,13 @@ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigne
20
25
  fee_token: config.feeToken,
21
26
  transaction: prePaymentTx,
22
27
  });
23
- if (fee_in_token < 0) {
24
- throw new Error(`Kora fee estimation returned a negative fee (${fee_in_token}). This indicates a server-side error.`);
28
+ if (fee_in_token == null) {
29
+ console.warn('[kora] fee_in_token is undefined defaulting to 0. ' +
30
+ 'If paid pricing is expected, check that the fee token is correctly configured on the server.');
31
+ }
32
+ const feeInToken = fee_in_token ?? 0;
33
+ if (feeInToken < 0) {
34
+ throw new Error(`Kora fee estimation returned a negative fee (${feeInToken}). This indicates a server-side error.`);
25
35
  }
26
36
  const currentIxs = 'instructions' in msgForEstimation
27
37
  ? msgForEstimation.instructions
@@ -31,9 +41,9 @@ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigne
31
41
  'The message structure may be incompatible with this version of the Kora SDK.');
32
42
  }
33
43
  // Replace placeholder with real fee amount, or strip it if fee is 0
34
- const finalIxs = fee_in_token > 0
35
- ? updatePaymentInstructionAmount(currentIxs, config.feePayerWallet, sourceTokenAccount, destinationTokenAccount, fee_in_token, config.tokenProgramId)
36
- : removePaymentInstruction(currentIxs, sourceTokenAccount, destinationTokenAccount, config.feePayerWallet, config.tokenProgramId);
44
+ const finalIxs = feeInToken > 0
45
+ ? updatePaymentInstructionAmount(currentIxs, userSigner, sourceTokenAccount, destinationTokenAccount, feeInToken, config.tokenProgramId)
46
+ : removePaymentInstruction(currentIxs, sourceTokenAccount, destinationTokenAccount, userSigner, config.tokenProgramId);
37
47
  const resolvedMsg = pipe(createTransactionMessage({ version: 0 }), m => setTransactionMessageFeePayerSigner(payerSigner, m), m => setTransactionMessageLifetimeUsingBlockhash({
38
48
  blockhash: blockhash(bh),
39
49
  lastValidBlockHeight: BigInt(Number.MAX_SAFE_INTEGER),
@@ -43,7 +53,10 @@ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigne
43
53
  else {
44
54
  finalTx = prePaymentTx;
45
55
  }
46
- const result = await koraClient.signAndSendTransaction({ transaction: finalTx });
56
+ const result = await koraClient.signAndSendTransaction({
57
+ transaction: finalTx,
58
+ user_id: config.userId,
59
+ });
47
60
  if (result.signature) {
48
61
  return signature(result.signature);
49
62
  }
@@ -1,50 +1,110 @@
1
- import type { KoraKitClientConfig } from '../types/index.js';
2
- /** The type returned by {@link createKitKoraClient}. */
3
- export type KoraKitClient = Awaited<ReturnType<typeof createKitKoraClient>>;
1
+ import { type ClientWithIdentity } from '@solana/kit';
2
+ import type { KoraBundleConfig, KoraKitClientConfig } from '../types/index.js';
4
3
  /**
5
- * Creates a Kora Kit client composed from Kit plugins.
4
+ * Kora bundle plugin.
5
+ *
6
+ * Composes RPC + payer + Kora RPC methods + transaction planning/execution into a single
7
+ * plugin that mirrors the shape of `solanaRpc` from `@solana/kit-plugin-rpc`.
6
8
  *
7
- * The returned client satisfies `ClientWithPayer`, `ClientWithTransactionPlanning`,
8
- * and `ClientWithTransactionSending`, making it composable with Kit program plugins.
9
+ * The caller's signer is read from `client.identity` install `identity()` (or `signer()`)
10
+ * from `@solana/kit-plugin-signer` before this plugin. The fee payer (Kora's address) is
11
+ * fetched from the Kora node and installed internally as a noop signer, overriding any
12
+ * `payer` already on the client.
9
13
  *
10
14
  * @beta This API is experimental and may change in future releases.
11
15
  *
12
16
  * @example
13
- * ```typescript
14
- * import { createKitKoraClient } from '@solana/kora';
15
- * import { address } from '@solana/kit';
16
- *
17
- * const client = await createKitKoraClient({
18
- * endpoint: 'https://kora.example.com',
19
- * rpcUrl: 'https://api.mainnet-beta.solana.com',
20
- * feeToken: address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
21
- * feePayerWallet: userSigner,
22
- * });
23
- *
24
- * const result = await client.sendTransaction([myInstruction]);
17
+ * ```ts
18
+ * import { createClient } from '@solana/kit';
19
+ * import { identity } from '@solana/kit-plugin-signer';
20
+ * import { kora } from '@solana/kora';
21
+ *
22
+ * const client = await createClient()
23
+ * .use(identity(userSigner))
24
+ * .use(kora({
25
+ * endpoint: 'https://kora.example.com',
26
+ * rpcUrl: 'https://api.mainnet-beta.solana.com',
27
+ * feeToken: address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
28
+ * }));
29
+ *
30
+ * const signature = await client.sendTransaction([myInstruction]);
25
31
  * ```
26
32
  */
27
- export declare function createKitKoraClient(config: KoraKitClientConfig): Promise<import("@solana/kit").Client<import("@solana/kit").ClientWithTransactionPlanning & import("@solana/kit").ClientWithTransactionSending & object & {
33
+ export declare function kora(config: KoraBundleConfig): <T extends ClientWithIdentity>(client: T) => Promise<Omit<Omit<Omit<Omit<Omit<T, "payer"> & {
34
+ payer: import("@solana/kit").NoopSigner<string>;
35
+ }, "rpc"> & {
28
36
  rpc: import("@solana/kit").Rpc<import("@solana/kit").RequestAirdropApi & import("@solana/kit").GetAccountInfoApi & import("@solana/kit").GetBalanceApi & import("@solana/kit").GetBlockApi & import("@solana/kit").GetBlockCommitmentApi & import("@solana/kit").GetBlockHeightApi & import("@solana/kit").GetBlockProductionApi & import("@solana/kit").GetBlocksApi & import("@solana/kit").GetBlocksWithLimitApi & import("@solana/kit").GetBlockTimeApi & import("@solana/kit").GetClusterNodesApi & import("@solana/kit").GetEpochInfoApi & import("@solana/kit").GetEpochScheduleApi & import("@solana/kit").GetFeeForMessageApi & import("@solana/kit").GetFirstAvailableBlockApi & import("@solana/kit").GetGenesisHashApi & import("@solana/kit").GetHealthApi & import("@solana/kit").GetHighestSnapshotSlotApi & import("@solana/kit").GetIdentityApi & import("@solana/kit").GetInflationGovernorApi & import("@solana/kit").GetInflationRateApi & import("@solana/kit").GetInflationRewardApi & import("@solana/kit").GetLargestAccountsApi & import("@solana/kit").GetLatestBlockhashApi & import("@solana/kit").GetLeaderScheduleApi & import("@solana/kit").GetMaxRetransmitSlotApi & import("@solana/kit").GetMaxShredInsertSlotApi & import("@solana/kit").GetMinimumBalanceForRentExemptionApi & import("@solana/kit").GetMultipleAccountsApi & import("@solana/kit").GetProgramAccountsApi & import("@solana/kit").GetRecentPerformanceSamplesApi & import("@solana/kit").GetRecentPrioritizationFeesApi & import("@solana/kit").GetSignaturesForAddressApi & import("@solana/kit").GetSignatureStatusesApi & import("@solana/kit").GetSlotApi & import("@solana/kit").GetSlotLeaderApi & import("@solana/kit").GetSlotLeadersApi & import("@solana/kit").GetStakeMinimumDelegationApi & import("@solana/kit").GetSupplyApi & import("@solana/kit").GetTokenAccountBalanceApi & import("@solana/kit").GetTokenAccountsByDelegateApi & import("@solana/kit").GetTokenAccountsByOwnerApi & import("@solana/kit").GetTokenLargestAccountsApi & import("@solana/kit").GetTokenSupplyApi & import("@solana/kit").GetTransactionApi & import("@solana/kit").GetTransactionCountApi & import("@solana/kit").GetVersionApi & import("@solana/kit").GetVoteAccountsApi & import("@solana/kit").IsBlockhashValidApi & import("@solana/kit").MinimumLedgerSlotApi & import("@solana/kit").SendTransactionApi & import("@solana/kit").SimulateTransactionApi>;
29
- rpcSubscriptions: import("@solana/kit").RpcSubscriptions<import("@solana/kit").SolanaRpcSubscriptionsApi>;
30
37
  } & {
31
38
  kora: {
39
+ estimateBundleFee(request: import("../types/index.js").EstimateBundleFeeRequest): Promise<import("../types/index.js").KitEstimateBundleFeeResponse>;
32
40
  estimateTransactionFee(request: import("../types/index.js").EstimateTransactionFeeRequest): Promise<import("../types/index.js").KitEstimateFeeResponse>;
33
41
  getBlockhash(): Promise<import("../types/index.js").KitBlockhashResponse>;
34
42
  getConfig(): Promise<import("../types/index.js").KitConfigResponse>;
35
43
  getPayerSigner(): Promise<import("../types/index.js").KitPayerSignerResponse>;
36
44
  getPaymentInstruction(request: import("../types/index.js").GetPaymentInstructionRequest): Promise<import("../types/index.js").KitPaymentInstructionResponse>;
37
45
  getSupportedTokens(): Promise<import("../types/index.js").KitSupportedTokensResponse>;
46
+ getVersion(): Promise<import("../types/index.js").GetVersionResponse>;
47
+ signAndSendBundle(request: import("../types/index.js").SignAndSendBundleRequest): Promise<import("../types/index.js").KitSignAndSendBundleResponse>;
38
48
  signAndSendTransaction(request: import("../types/index.js").SignAndSendTransactionRequest): Promise<import("../types/index.js").KitSignAndSendTransactionResponse>;
49
+ signBundle(request: import("../types/index.js").SignBundleRequest): Promise<import("../types/index.js").KitSignBundleResponse>;
39
50
  signTransaction(request: import("../types/index.js").SignTransactionRequest): Promise<import("../types/index.js").KitSignTransactionResponse>;
40
- transferTransaction(request: import("../types/index.js").TransferTransactionRequest): Promise<import("../types/index.js").KitTransferTransactionResponse>;
41
51
  };
42
- } & {
43
- payer: import("@solana/kit").TransactionSigner;
44
52
  } & {
45
53
  paymentAddress: import("@solana/kit").Address | undefined;
46
- } & {
54
+ }, "transactionPlanner"> & {
47
55
  transactionPlanner: import("@solana/kit").TransactionPlanner;
56
+ }, "transactionPlanExecutor"> & {
57
+ transactionPlanExecutor: import("@solana/kit").TransactionPlanExecutor;
58
+ }, keyof import("@solana/kit").ClientWithTransactionPlanning | keyof import("@solana/kit").ClientWithTransactionSending> & import("@solana/kit").ClientWithTransactionPlanning & import("@solana/kit").ClientWithTransactionSending>;
59
+ /**
60
+ * The type returned by {@link createKitKoraClient}.
61
+ *
62
+ * @deprecated Derive the client type from your own `createClient().use(...).use(kora(...))`
63
+ * composition instead. Will be removed in 0.4.0.
64
+ */
65
+ export type KoraKitClient = Awaited<ReturnType<typeof createKitKoraClient>>;
66
+ /**
67
+ * Creates a Kora Kit client composed from Kit plugins.
68
+ *
69
+ * @beta This API is experimental and may change in future releases.
70
+ *
71
+ * @deprecated Compose with the {@link kora} plugin instead:
72
+ * ```ts
73
+ * import { createClient } from '@solana/kit';
74
+ * import { identity } from '@solana/kit-plugin-signer';
75
+ * import { kora } from '@solana/kora';
76
+ *
77
+ * const client = await createClient()
78
+ * .use(identity(userSigner))
79
+ * .use(kora({ endpoint, rpcUrl, feeToken }));
80
+ * ```
81
+ * Will be removed in 0.4.0.
82
+ */
83
+ export declare function createKitKoraClient(config: KoraKitClientConfig): Promise<import("@solana/kit").Client<Omit<Omit<Omit<Omit<Omit<Omit<object, "identity"> & {
84
+ identity: import("@solana/kit").TransactionSigner;
85
+ }, "payer"> & {
86
+ payer: import("@solana/kit").NoopSigner<string>;
87
+ }, "rpc"> & {
88
+ rpc: import("@solana/kit").Rpc<import("@solana/kit").RequestAirdropApi & import("@solana/kit").GetAccountInfoApi & import("@solana/kit").GetBalanceApi & import("@solana/kit").GetBlockApi & import("@solana/kit").GetBlockCommitmentApi & import("@solana/kit").GetBlockHeightApi & import("@solana/kit").GetBlockProductionApi & import("@solana/kit").GetBlocksApi & import("@solana/kit").GetBlocksWithLimitApi & import("@solana/kit").GetBlockTimeApi & import("@solana/kit").GetClusterNodesApi & import("@solana/kit").GetEpochInfoApi & import("@solana/kit").GetEpochScheduleApi & import("@solana/kit").GetFeeForMessageApi & import("@solana/kit").GetFirstAvailableBlockApi & import("@solana/kit").GetGenesisHashApi & import("@solana/kit").GetHealthApi & import("@solana/kit").GetHighestSnapshotSlotApi & import("@solana/kit").GetIdentityApi & import("@solana/kit").GetInflationGovernorApi & import("@solana/kit").GetInflationRateApi & import("@solana/kit").GetInflationRewardApi & import("@solana/kit").GetLargestAccountsApi & import("@solana/kit").GetLatestBlockhashApi & import("@solana/kit").GetLeaderScheduleApi & import("@solana/kit").GetMaxRetransmitSlotApi & import("@solana/kit").GetMaxShredInsertSlotApi & import("@solana/kit").GetMinimumBalanceForRentExemptionApi & import("@solana/kit").GetMultipleAccountsApi & import("@solana/kit").GetProgramAccountsApi & import("@solana/kit").GetRecentPerformanceSamplesApi & import("@solana/kit").GetRecentPrioritizationFeesApi & import("@solana/kit").GetSignaturesForAddressApi & import("@solana/kit").GetSignatureStatusesApi & import("@solana/kit").GetSlotApi & import("@solana/kit").GetSlotLeaderApi & import("@solana/kit").GetSlotLeadersApi & import("@solana/kit").GetStakeMinimumDelegationApi & import("@solana/kit").GetSupplyApi & import("@solana/kit").GetTokenAccountBalanceApi & import("@solana/kit").GetTokenAccountsByDelegateApi & import("@solana/kit").GetTokenAccountsByOwnerApi & import("@solana/kit").GetTokenLargestAccountsApi & import("@solana/kit").GetTokenSupplyApi & import("@solana/kit").GetTransactionApi & import("@solana/kit").GetTransactionCountApi & import("@solana/kit").GetVersionApi & import("@solana/kit").GetVoteAccountsApi & import("@solana/kit").IsBlockhashValidApi & import("@solana/kit").MinimumLedgerSlotApi & import("@solana/kit").SendTransactionApi & import("@solana/kit").SimulateTransactionApi>;
48
89
  } & {
90
+ kora: {
91
+ estimateBundleFee(request: import("../types/index.js").EstimateBundleFeeRequest): Promise<import("../types/index.js").KitEstimateBundleFeeResponse>;
92
+ estimateTransactionFee(request: import("../types/index.js").EstimateTransactionFeeRequest): Promise<import("../types/index.js").KitEstimateFeeResponse>;
93
+ getBlockhash(): Promise<import("../types/index.js").KitBlockhashResponse>;
94
+ getConfig(): Promise<import("../types/index.js").KitConfigResponse>;
95
+ getPayerSigner(): Promise<import("../types/index.js").KitPayerSignerResponse>;
96
+ getPaymentInstruction(request: import("../types/index.js").GetPaymentInstructionRequest): Promise<import("../types/index.js").KitPaymentInstructionResponse>;
97
+ getSupportedTokens(): Promise<import("../types/index.js").KitSupportedTokensResponse>;
98
+ getVersion(): Promise<import("../types/index.js").GetVersionResponse>;
99
+ signAndSendBundle(request: import("../types/index.js").SignAndSendBundleRequest): Promise<import("../types/index.js").KitSignAndSendBundleResponse>;
100
+ signAndSendTransaction(request: import("../types/index.js").SignAndSendTransactionRequest): Promise<import("../types/index.js").KitSignAndSendTransactionResponse>;
101
+ signBundle(request: import("../types/index.js").SignBundleRequest): Promise<import("../types/index.js").KitSignBundleResponse>;
102
+ signTransaction(request: import("../types/index.js").SignTransactionRequest): Promise<import("../types/index.js").KitSignTransactionResponse>;
103
+ };
104
+ } & {
105
+ paymentAddress: import("@solana/kit").Address | undefined;
106
+ }, "transactionPlanner"> & {
107
+ transactionPlanner: import("@solana/kit").TransactionPlanner;
108
+ }, "transactionPlanExecutor"> & {
49
109
  transactionPlanExecutor: import("@solana/kit").TransactionPlanExecutor;
50
- }>>;
110
+ }, keyof import("@solana/kit").ClientWithTransactionPlanning | keyof import("@solana/kit").ClientWithTransactionSending> & import("@solana/kit").ClientWithTransactionPlanning & import("@solana/kit").ClientWithTransactionSending>>;
@@ -1,67 +1,97 @@
1
- import { address, createEmptyClient, createNoopSigner, createSolanaRpc } from '@solana/kit';
1
+ import { address, createClient, createNoopSigner, createSolanaRpc, pipe } from '@solana/kit';
2
2
  import { planAndSendTransactions, transactionPlanExecutor as transactionPlanExecutorPlugin, transactionPlanner as transactionPlannerPlugin, } from '@solana/kit-plugin-instruction-plan';
3
- import { payer } from '@solana/kit-plugin-payer';
4
- import { rpc } from '@solana/kit-plugin-rpc';
3
+ import { solanaRpcConnection } from '@solana/kit-plugin-rpc';
4
+ import { identity, payer } from '@solana/kit-plugin-signer';
5
5
  import { estimateAndUpdateProvisoryComputeUnitLimitFactory, estimateComputeUnitLimitFactory, } from '@solana-program/compute-budget';
6
6
  import { KoraClient } from '../client.js';
7
+ import { koraPlugin } from '../plugin.js';
7
8
  import { createKoraTransactionPlanExecutor } from './executor.js';
8
9
  import { buildPlaceholderPaymentInstruction, koraPaymentAddress } from './payment.js';
9
10
  import { buildComputeBudgetInstructions, createKoraTransactionPlanner } from './planner.js';
10
- import { koraPlugin } from './plugin.js';
11
11
  /**
12
- * Creates a Kora Kit client composed from Kit plugins.
12
+ * Kora bundle plugin.
13
+ *
14
+ * Composes RPC + payer + Kora RPC methods + transaction planning/execution into a single
15
+ * plugin that mirrors the shape of `solanaRpc` from `@solana/kit-plugin-rpc`.
13
16
  *
14
- * The returned client satisfies `ClientWithPayer`, `ClientWithTransactionPlanning`,
15
- * and `ClientWithTransactionSending`, making it composable with Kit program plugins.
17
+ * The caller's signer is read from `client.identity` install `identity()` (or `signer()`)
18
+ * from `@solana/kit-plugin-signer` before this plugin. The fee payer (Kora's address) is
19
+ * fetched from the Kora node and installed internally as a noop signer, overriding any
20
+ * `payer` already on the client.
16
21
  *
17
22
  * @beta This API is experimental and may change in future releases.
18
23
  *
19
24
  * @example
20
- * ```typescript
21
- * import { createKitKoraClient } from '@solana/kora';
22
- * import { address } from '@solana/kit';
25
+ * ```ts
26
+ * import { createClient } from '@solana/kit';
27
+ * import { identity } from '@solana/kit-plugin-signer';
28
+ * import { kora } from '@solana/kora';
29
+ *
30
+ * const client = await createClient()
31
+ * .use(identity(userSigner))
32
+ * .use(kora({
33
+ * endpoint: 'https://kora.example.com',
34
+ * rpcUrl: 'https://api.mainnet-beta.solana.com',
35
+ * feeToken: address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
36
+ * }));
37
+ *
38
+ * const signature = await client.sendTransaction([myInstruction]);
39
+ * ```
40
+ */
41
+ export function kora(config) {
42
+ return async (client) => {
43
+ const koraClient = new KoraClient({
44
+ apiKey: config.apiKey,
45
+ getRecaptchaToken: config.getRecaptchaToken,
46
+ hmacSecret: config.hmacSecret,
47
+ rpcUrl: config.endpoint,
48
+ });
49
+ const { signer_address, payment_address } = await koraClient.getPayerSigner();
50
+ const paymentAddr = payment_address ? address(payment_address) : undefined;
51
+ const payerSigner = createNoopSigner(address(signer_address));
52
+ const computeBudgetIxs = buildComputeBudgetInstructions(config);
53
+ const solanaRpc = createSolanaRpc(config.rpcUrl);
54
+ const hasCuEstimation = config.computeUnitLimit === undefined;
55
+ const resolveProvisoryComputeUnitLimit = hasCuEstimation
56
+ ? estimateAndUpdateProvisoryComputeUnitLimitFactory(estimateComputeUnitLimitFactory({ rpc: solanaRpc }))
57
+ : undefined;
58
+ const userSigner = client.identity;
59
+ const payment = paymentAddr
60
+ ? await buildPlaceholderPaymentInstruction(userSigner, paymentAddr, config.feeToken, config.tokenProgramId)
61
+ : undefined;
62
+ const koraTransactionPlanner = createKoraTransactionPlanner(payerSigner, computeBudgetIxs, payment?.instruction, hasCuEstimation);
63
+ const koraTransactionPlanExecutor = createKoraTransactionPlanExecutor(koraClient, config, userSigner, payerSigner, payment
64
+ ? {
65
+ destinationTokenAccount: payment.destinationTokenAccount,
66
+ sourceTokenAccount: payment.sourceTokenAccount,
67
+ }
68
+ : undefined, resolveProvisoryComputeUnitLimit);
69
+ return pipe(client, payer(payerSigner), solanaRpcConnection(config.rpcUrl), koraPlugin({
70
+ endpoint: config.endpoint,
71
+ koraClient,
72
+ }), koraPaymentAddress(paymentAddr), transactionPlannerPlugin(koraTransactionPlanner), transactionPlanExecutorPlugin(koraTransactionPlanExecutor), planAndSendTransactions());
73
+ };
74
+ }
75
+ /**
76
+ * Creates a Kora Kit client composed from Kit plugins.
77
+ *
78
+ * @beta This API is experimental and may change in future releases.
23
79
  *
24
- * const client = await createKitKoraClient({
25
- * endpoint: 'https://kora.example.com',
26
- * rpcUrl: 'https://api.mainnet-beta.solana.com',
27
- * feeToken: address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
28
- * feePayerWallet: userSigner,
29
- * });
80
+ * @deprecated Compose with the {@link kora} plugin instead:
81
+ * ```ts
82
+ * import { createClient } from '@solana/kit';
83
+ * import { identity } from '@solana/kit-plugin-signer';
84
+ * import { kora } from '@solana/kora';
30
85
  *
31
- * const result = await client.sendTransaction([myInstruction]);
86
+ * const client = await createClient()
87
+ * .use(identity(userSigner))
88
+ * .use(kora({ endpoint, rpcUrl, feeToken }));
32
89
  * ```
90
+ * Will be removed in 0.4.0.
33
91
  */
92
+ // TODO: Bundle support — the plan/execute pipeline currently handles single transactions only.
93
+ // For Jito bundles, users must manually encode transactions and call `client.kora.signAndSendBundle()`.
34
94
  export async function createKitKoraClient(config) {
35
- const koraClient = new KoraClient({
36
- apiKey: config.apiKey,
37
- hmacSecret: config.hmacSecret,
38
- rpcUrl: config.endpoint,
39
- });
40
- const { signer_address, payment_address } = await koraClient.getPayerSigner();
41
- const paymentAddr = payment_address ? address(payment_address) : undefined;
42
- const payerSigner = createNoopSigner(address(signer_address));
43
- const computeBudgetIxs = buildComputeBudgetInstructions(config);
44
- const solanaRpc = createSolanaRpc(config.rpcUrl);
45
- const hasCuEstimation = config.computeUnitLimit === undefined;
46
- const resolveProvisoryComputeUnitLimit = hasCuEstimation
47
- ? estimateAndUpdateProvisoryComputeUnitLimitFactory(estimateComputeUnitLimitFactory({ rpc: solanaRpc }))
48
- : undefined;
49
- const payment = paymentAddr
50
- ? await buildPlaceholderPaymentInstruction(config.feePayerWallet, paymentAddr, config.feeToken, config.tokenProgramId)
51
- : undefined;
52
- const koraTransactionPlanner = createKoraTransactionPlanner(payerSigner, computeBudgetIxs, payment?.instruction, hasCuEstimation);
53
- const koraTransactionPlanExecutor = createKoraTransactionPlanExecutor(koraClient, config, payerSigner, payment
54
- ? {
55
- destinationTokenAccount: payment.destinationTokenAccount,
56
- sourceTokenAccount: payment.sourceTokenAccount,
57
- }
58
- : undefined, resolveProvisoryComputeUnitLimit);
59
- return createEmptyClient()
60
- .use(rpc(config.rpcUrl))
61
- .use(koraPlugin({ apiKey: config.apiKey, endpoint: config.endpoint, hmacSecret: config.hmacSecret }))
62
- .use(payer(payerSigner))
63
- .use(koraPaymentAddress(paymentAddr))
64
- .use(transactionPlannerPlugin(koraTransactionPlanner))
65
- .use(transactionPlanExecutorPlugin(koraTransactionPlanExecutor))
66
- .use(planAndSendTransactions());
95
+ const { feePayerWallet, ...bundleConfig } = config;
96
+ return await createClient().use(identity(feePayerWallet)).use(kora(bundleConfig));
67
97
  }
@@ -27,7 +27,7 @@ export async function buildPlaceholderPaymentInstruction(feePayerWallet, payment
27
27
  authority: feePayerWallet,
28
28
  destination: destinationTokenAccount,
29
29
  source: sourceTokenAccount,
30
- });
30
+ }, { programAddress: tokenProgram });
31
31
  return { destinationTokenAccount, instruction, sourceTokenAccount };
32
32
  }
33
33
  function isPlaceholderPaymentInstruction(ix, sourceTokenAccount, destinationTokenAccount, feePayerWallet, tokenProgramId) {
@@ -50,12 +50,13 @@ export function updatePaymentInstructionAmount(instructions, feePayerWallet, sou
50
50
  return ix;
51
51
  }
52
52
  replaced = true;
53
+ const tokenProgram = tokenProgramId ?? TOKEN_PROGRAM_ADDRESS;
53
54
  return getTransferInstruction({
54
55
  amount,
55
56
  authority: feePayerWallet,
56
57
  destination: destinationTokenAccount,
57
58
  source: sourceTokenAccount,
58
- });
59
+ }, { programAddress: tokenProgram });
59
60
  });
60
61
  if (!replaced) {
61
62
  throw new Error('Failed to update payment instruction: no matching placeholder transfer instruction found. ' +
@@ -1,4 +1,4 @@
1
1
  import { type Instruction, type TransactionSigner } from '@solana/kit';
2
- import type { KoraKitClientConfig } from '../types/index.js';
3
- export declare function buildComputeBudgetInstructions(config: KoraKitClientConfig): Instruction[];
2
+ import type { KoraBundleConfig } from '../types/index.js';
3
+ export declare function buildComputeBudgetInstructions(config: KoraBundleConfig): Instruction[];
4
4
  export declare function createKoraTransactionPlanner(payerSigner: TransactionSigner, computeBudgetIxs: Instruction[], paymentInstruction: Instruction | undefined, hasCuEstimation: boolean): import("@solana/kit").TransactionPlanner;
@@ -0,0 +1,85 @@
1
+ import type { EstimateBundleFeeRequest, EstimateTransactionFeeRequest, GetPaymentInstructionRequest, GetVersionResponse, KitBlockhashResponse, KitConfigResponse, KitEstimateBundleFeeResponse, KitEstimateFeeResponse, KitPayerSignerResponse, KitPaymentInstructionResponse, KitSignAndSendBundleResponse, KitSignAndSendTransactionResponse, KitSignBundleResponse, KitSignTransactionResponse, KitSupportedTokensResponse, KoraPluginConfig, SignAndSendBundleRequest, SignAndSendTransactionRequest, SignBundleRequest, SignTransactionRequest } from './types/index.js';
2
+ /**
3
+ * Creates a Kora Kit plugin that adds Kora paymaster functionality to a Kit client.
4
+ *
5
+ * The plugin exposes all Kora RPC methods with Kit-typed responses (Address, Blockhash).
6
+ *
7
+ * **Note:** The plugin pattern with `createClient().use()` requires `@solana/kit` v6.8.0+.
8
+ * For older kit versions, use `KoraClient` directly instead.
9
+ *
10
+ * @param config - Plugin configuration
11
+ * @param config.endpoint - Kora RPC endpoint URL
12
+ * @param config.apiKey - Optional API key for authentication
13
+ * @param config.hmacSecret - Optional HMAC secret for signature-based authentication
14
+ * @returns A Kit plugin function that adds `.kora` to the client
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { createClient } from '@solana/kit';
19
+ * import { koraPlugin } from '@solana/kora';
20
+ *
21
+ * const client = createClient()
22
+ * .use(koraPlugin({ endpoint: 'https://kora.example.com' }));
23
+ *
24
+ * // All responses have Kit-typed fields
25
+ * const config = await client.kora.getConfig();
26
+ * // config.fee_payers is Address[] not string[]
27
+ *
28
+ * const { signer_pubkey } = await client.kora.signTransaction({ transaction: tx });
29
+ * // signer_pubkey is Address not string
30
+ * ```
31
+ */
32
+ export declare function koraPlugin(config: KoraPluginConfig): <T extends object>(c: T) => T & {
33
+ kora: {
34
+ /**
35
+ * Estimates the bundle fee with Kit-typed addresses.
36
+ */
37
+ estimateBundleFee(request: EstimateBundleFeeRequest): Promise<KitEstimateBundleFeeResponse>;
38
+ /**
39
+ * Estimates the transaction fee with Kit-typed addresses.
40
+ */
41
+ estimateTransactionFee(request: EstimateTransactionFeeRequest): Promise<KitEstimateFeeResponse>;
42
+ /**
43
+ * Gets the latest blockhash with Kit Blockhash type.
44
+ */
45
+ getBlockhash(): Promise<KitBlockhashResponse>;
46
+ /**
47
+ * Retrieves the current Kora server configuration with Kit-typed addresses.
48
+ */
49
+ getConfig(): Promise<KitConfigResponse>;
50
+ /**
51
+ * Retrieves the payer signer and payment destination with Kit-typed addresses.
52
+ */
53
+ getPayerSigner(): Promise<KitPayerSignerResponse>;
54
+ /**
55
+ * Creates a payment instruction with Kit-typed response.
56
+ */
57
+ getPaymentInstruction(request: GetPaymentInstructionRequest): Promise<KitPaymentInstructionResponse>;
58
+ /**
59
+ * Retrieves the list of tokens supported for fee payment with Kit-typed addresses.
60
+ */
61
+ getSupportedTokens(): Promise<KitSupportedTokensResponse>;
62
+ /**
63
+ * Gets the version of the Kora server.
64
+ */
65
+ getVersion(): Promise<GetVersionResponse>;
66
+ /**
67
+ * Signs and sends a bundle of transactions via Jito with Kit-typed response.
68
+ */
69
+ signAndSendBundle(request: SignAndSendBundleRequest): Promise<KitSignAndSendBundleResponse>;
70
+ /**
71
+ * Signs and sends a transaction with Kit-typed response.
72
+ */
73
+ signAndSendTransaction(request: SignAndSendTransactionRequest): Promise<KitSignAndSendTransactionResponse>;
74
+ /**
75
+ * Signs a bundle of transactions with Kit-typed response.
76
+ */
77
+ signBundle(request: SignBundleRequest): Promise<KitSignBundleResponse>;
78
+ /**
79
+ * Signs a transaction with Kit-typed response.
80
+ */
81
+ signTransaction(request: SignTransactionRequest): Promise<KitSignTransactionResponse>;
82
+ };
83
+ };
84
+ /** Type representing the Kora API exposed by the plugin */
85
+ export type KoraApi = ReturnType<ReturnType<typeof koraPlugin>>['kora'];