github anza-xyz/kit v7.1.0

3 hours ago

@solana/kit

v7.1.0 (2026-08-14)

Minor Changes

  • [@solana/errors, @solana/kit, @solana/react, @solana/subscribable] #1811 7022c26 Thanks @mcintyre94! - Add bridgeStoreToAsyncIterable to @solana/subscribable

    bridgeStoreToAsyncIterable adapts a ReactiveStreamStore into the pull-based AsyncIterable contract that consumers like TanStack Query's experimental_streamedQuery expect. It is now a public export of @solana/subscribable (and re-exported from @solana/kit). It was previously an internal helper of @solana/react, but it is not React- or TanStack-specific and is useful to any consumer that needs to drive a stream store by for await-ing it.

    The bridge only observes the store — consistent with the rest of the ecosystem, the caller owns the store's lifecycle (connect() it yourself, bound to the same signal, and reset() it when done). The bridge subscribes, seeds from the store's current snapshot, yields values, and unsubscribes when iteration ends.

    It throws the new SOLANA_ERROR__SUBSCRIBABLE__STREAM_CLOSED_WITHOUT_ERROR when a store closes in an error state with a nullish payload. This is the error useSubscriptionQuery and useTrackedDataQuery now surface in that case; the SWR bridge is unaffected.

  • [@solana/errors, @solana/offchain-messages] #1888 14a3e5b Thanks @mcintyre94! - Add an assertOffchainMessageV1Equal helper that asserts that a version 1 offchain message you received from an untrusted signer (eg. a wallet) is the message you expected it to sign. Verifying a signature proves only that the signer produced it over the bytes it handed back, not that those bytes represent the message you asked for, so assert this before verifying signatures with verifyOffchainMessageEnvelope. The helper compares the content and the required signatories, and reports each kind of mismatch with its own error code: the new SOLANA_ERROR__OFFCHAIN_MESSAGE__CONTENT_DOES_NOT_MATCH_EXPECTED and SOLANA_ERROR__OFFCHAIN_MESSAGE__REQUIRED_SIGNATORIES_DO_NOT_MATCH_EXPECTED. Required signatories are compared without regard to order, since a decoded message lists them in the order the specification mandates while yours may be in any order. It accepts an OffchainMessageV1 rather than the OffchainMessage union that decoding produces, so narrow the decoded message to a version 1 message before calling it.

  • [@solana/instruction-plans] #1915 9e7daea Thanks @mcintyre94! - Let the createTransactionPlanExecutor callback return the context of a successful result

    The executeTransactionMessage callback may now return the context that a successful result should carry, instead of a Signature or a Transaction. When it does, that context is used as-is: nothing is derived from it, and in particular getSignatureFromTransaction is never called on your behalf.

    const transactionPlanExecutor = createTransactionPlanExecutor({
      executeTransactionMessage: async (context, message) => {
        const transaction = await signTransactionMessageWithSigners(message);
        context.transaction = transaction;
    +   const signature = getSignatureFromTransaction(transaction);
        await sendAndConfirmTransaction(transaction, { commitment: 'confirmed' });
    -   return transaction;
    +   return { signature, transaction };
      },
    });

    Since a successful result always carries a signature, a returned context must include one — a callback that declares a custom context and forgets a property of it now fails to compile, rather than producing a result whose context is typed but undefined at runtime. That signature is also how the executor tells a returned context apart from a returned Transaction, which keeps its signatures in a signatures map and therefore never has one.

    The mutable context argument is unchanged and still serves the failure path: whatever the callback stores on it before it throws is preserved in the resulting FailedSingleTransactionPlanResult. On success the two are merged, with the returned context taking precedence, so a property stored but not returned is still reported.

    Returning a Signature or a Transaction is deprecated. Both still behave exactly as before — a returned signature is stored as context.signature, and a returned transaction is stored as context.transaction with its signature derived from it — and IDEs now flag those call sites, because createTransactionPlanExecutor gained a deprecated overload that only matches callbacks returning those types. Note that a config declared as TransactionPlanExecutorConfig up front is not flagged, since that type permits either return style.

    Prefer returning a context, since deriving a signature from a transaction throws SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING when the fee payer slot is empty. An executor that deliberately produces partially signed transactions — signed by an authority, to be paid for and submitted by a relayer later — can now succeed by returning its own signature alongside the transaction. Dropping the signature from a successful result's context altogether remains impossible, since SuccessfulSingleTransactionPlanResult guarantees one.

    Failure handling is unchanged, including the signature still derived from a transaction left on the context when the callback throws. Since the callback never returned anything in that case, there is nothing to bypass that derivation, so a callback working with fee-payer-unsigned transactions should avoid storing them on the context — otherwise deriving a signature from one replaces the error it meant to report.

  • [@solana/kit] #1898 4a5f717 Thanks @lorisleiva! - Add helpers to create client interfaces from a raw Rpc

    Add createClientWithGetMinimumBalanceFromRpc, createClientWithFetchAccountsFromRpc and createClientWithInterfacesFromRpc to @solana/kit. These convenience helpers let consumers that only have a raw Rpc object construct the corresponding client interfaces (ClientWithGetMinimumBalance and ClientWithFetchAccounts) without assembling a full Kit client. createClientWithInterfacesFromRpc fills in whichever interfaces the RPC supports and narrows its return type accordingly.

  • [@solana/kit] #1824 b47feb6 Thanks @mcintyre94! - Re-export @solana/promises from @solana/kit

    @solana/kit now re-exports the @solana/promises package, so its helpers — isAbortError, getAbortablePromise, and safeRace — are available directly from @solana/kit without a separate dependency. This is particularly useful alongside @solana/react's useAction, whose superseded or aborted dispatches reject with an AbortError that callers filter using isAbortError.

  • [@solana/plugin-interfaces] #1897 aa0b625 Thanks @lorisleiva! - Add a ClientWithFetchAccounts interface

    This new plugin interface represents a client that can fetch the encoded content of accounts from their addresses via a fetchAccounts(addresses, config?) method. Like the other @solana/plugin-interfaces capabilities, it lets plugins provide or require account-fetching without coupling to a concrete RPC. The returned array matches the provided addresses in length and order, using MaybeEncodedAccount to represent accounts that may not exist.

  • [@solana/react] #1876 d6a1adb Thanks @mcintyre94! - Add usePayer and useIdentity React hooks. Each reads the corresponding value off the client and, when the client advertises subscribeToPayer/subscribeToIdentity, subscribes so the returned signer always reflects the latest payer/identity. Clients whose value is fixed fall back to a one-time read.

    If the plugin value throws (for example as the wallet plugin does when it owns payer/identity and a wallet is not connected), this is surfaced as undefined in the hooks.

  • [@solana/react] #1841 94f49bb Thanks @mcintyre94! - Make the TClient type parameter of useClient required by removing its object default, matching useClientCapability. Callers should always pass their client's shape (typically an exported AppClient type) so installed capabilities are typed at the call site.

    - const client = useClient();
    + const client = useClient<AppClient>();
  • [@solana/react] #1869 2193459 Thanks @mcintyre94! - Add usePlanTransaction, usePlanTransactions, useSendTransaction, and useSendTransactions hooks for driving a client's transaction-planning and -sending capabilities as reactive actions.

  • [@solana/react] #1879 c27ce2f Thanks @mcintyre94! - Add a useAirdrop hook that wraps a client's airdrop capability (ClientWithAirdrop) as a tracked useAction. dispatch(address, amount) requests an airdrop with an injected AbortSignal, resolving with the transaction Signature (or undefined when the airdrop is applied without a transaction).

  • [@solana/rpc-api] #1776 c8235ca Thanks @mcintyre94! - Add the getTransactionsForAddress RPC method type. This method combines address-history discovery and per-transaction fetching into a single query, with server-side filtering, bidirectional sorting, and cursor-based pagination. It will be part of the upcoming solana-rpc spec and is part of the solana-rpc/superbank project, and is already available from major RPC providers.

    It supports both signatures and full (json/jsonParsed/base58/base64) response modes. The shared transaction metadata types also gain an optional meta.costUnits field, which surfaces on getTransaction as well.

  • [@solana/rpc-transformers] #1919 80b3756 Thanks @amilz! - Stop upcasting token balance uiAmount and related numerics to bigint

    The response transformer upcasts every JSON integer to a bigint unless its keypath appears in an allow-list. Because the upcast only applies to integers, uiTokenAmount.uiAmount — an f64 on the server — arrived as a bigint when the balance happened to be a whole number and as a number when it was fractional, so its declared type was correct for some values and wrong for others.

    • uiTokenAmount.uiAmount is now allow-listed on getTransaction, getBlock, and getTransactionsForAddress token balances.
    • simulateTransaction had no token balance keypaths allow-listed at all, so accountIndex and uiTokenAmount.decimals were upcast there as well. All three are now allow-listed.

    @solana/rpc-transformers additionally exports a new tokenBalancesConfigs array of token-balance-relative keypaths, alongside the existing innerInstructionsConfigs and messageConfig.

  • [@solana/transaction-introspection] #1814 c45d5e0 Thanks @mcintyre94! - decodeTransactionFromRpcResponse now accepts confirmed transactions from any RPC method that returns them, not just getTransaction. It reads only the shared transaction / meta / version envelope, so getTransactionsForAddress results (map over its data array) and getBlock results (map over its transactions array, with transactionDetails: 'full') decode identically, including legacy transactions fetched without maxSupportedTransactionVersion. The 'json' overload now types its omitted transaction as never rather than an optional Transaction, reflecting that the JSON path never yields re-encodable wire bytes.

Patch Changes

  • [@solana/codecs-data-structures] #1911 8c9eece Thanks @latent-9! - Fix getBitArrayEncoder returning the wrong next offset. Its write returned size instead of offset + size, so a bit array placed before another field in a struct or tuple was overwritten by the following field. It now returns offset + size, matching the decoder and the other codecs.

  • [@solana/codecs-data-structures] #1884 da10c5a Thanks @Swift42! - Avoid copying the remaining buffer in getArrayDecoder's emptiness check

    getArrayDecoder's read() tested for an empty byte array with bytes.slice(offset).length === 0, which allocates and copies every byte from offset to the end just to read .length off the result. On large accounts containing many prefixed arrays, maps, or sets this made decoding quadratic in account size. The check is now the equivalent O(1) comparison offset >= bytes.length. getMapDecoder and getSetDecoder delegate to getArrayDecoder and benefit as well.

  • [@solana/codecs-data-structures] #1809 204ed6e Thanks @mcintyre94! - Allow boolean predicates passed to getPatternMatchCodec and getPatternMatchEncoder to narrow to a subtype of the variant's value type. Previously, matching against codecs whose value type is a union — such as the number codecs, whose encode type is number | bigint — forced predicates to be typed against the full union (e.g. (value: number | bigint) => …). The predicate parameter is now checked bivariantly, so a narrower predicate like (value: number) => … is accepted, mirroring the ergonomics of getPredicateCodec and getPredicateEncoder.

  • [@solana/kit, @solana/plugin-core] #1883 a900eeb Thanks @mcintyre94! - Fix withCleanup throwing DisposableStack is not defined on Safari

    withCleanup constructed a DisposableStack unconditionally, but Safari has not shipped explicit resource management — as of Safari 27 it provides neither DisposableStack nor Symbol.dispose — so any plugin that registers a cleanup function threw ReferenceError: Can't find variable: DisposableStack while the client was being built.

    The runtime's own DisposableStack is still used whenever it exists. Only where it is missing does withCleanup fall back to an internal stack that reproduces the behaviour it depends on. The withCleanup test suite now runs twice, once against each stack, so the two cannot drift apart.

    Note that this fixes disposal on Safari but not using declarations in your own code, which additionally need a Symbol.dispose polyfill; disposing a client explicitly works either way.

  • [@solana/react] #1907 9d6be07 Thanks @mcintyre94! - Widen the @solana/kit peer dependency of @solana/react from an exact version to a caret range. @solana/react previously declared "@solana/kit": "workspace:*", which publishes as an exact pin ("@solana/kit": "7.0.0"), so a consumer who advanced @solana/kit without advancing @solana/react in the same step hit an unsatisfiable peer range even though the two are compatible. It now declares workspace:^ and publishes as ^7.1.0. The two packages continue to be released in lockstep at identical versions, so this does not loosen which combinations are actually shipped — it only stops describing a compatible pair as incompatible.

  • [@solana/react] #1825 d54b899 Thanks @mcintyre94! - Bump the @wallet-standard/ui and @wallet-standard/ui-registry dependencies to ^1.0.3 and ^1.1.1 respectively. The 1.1.x registry line is a backward-compatible superset that continues to export the names @solana/react relies on, and aligning with it lets consumers that also pull in @solana/kit-plugin-wallet resolve a single, shared copy of the wallet-standard UI registry (which is a runtime singleton) instead of splitting across two incompatible copies.

  • [@solana/rpc-api] #1919 80b3756 Thanks @amilz! - Stop upcasting token balance uiAmount and related numerics to bigint

    The response transformer upcasts every JSON integer to a bigint unless its keypath appears in an allow-list. Because the upcast only applies to integers, uiTokenAmount.uiAmount — an f64 on the server — arrived as a bigint when the balance happened to be a whole number and as a number when it was fractional, so its declared type was correct for some values and wrong for others.

    • uiTokenAmount.uiAmount is now allow-listed on getTransaction, getBlock, and getTransactionsForAddress token balances.
    • simulateTransaction had no token balance keypaths allow-listed at all, so accountIndex and uiTokenAmount.decimals were upcast there as well. All three are now allow-listed.

    @solana/rpc-transformers additionally exports a new tokenBalancesConfigs array of token-balance-relative keypaths, alongside the existing innerInstructionsConfigs and messageConfig.

  • [@solana/rpc-api] #1917 82c4ceb Thanks @amilz! - Stop upcasting transaction version to bigint

    The response transformer upcasts every JSON integer to a bigint unless its keypath appears in an allow-list. version was missing from that allow-list on getTransaction, getBlock transactions, and getTransactionsForAddress, so it arrived at runtime as 0n while still typechecking as TransactionVersion ('legacy' | 0 | 1).

    A check like if (transaction.version === 0) therefore compiled cleanly and was always false, with no compiler error and no runtime error. The keypath is now allow-listed and version arrives as a number, matching its declared type.

  • [@solana/transaction-messages] #1874 327760c Thanks @mcintyre94! - Update type of compressTransactionMessageUsingAddressLookupTables to reject v1 transactions

Don't miss a new kit release

NewReleases is sending notifications on new releases.