@solana/react 7.0.0 → 7.1.0-canary-20260812160611

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.
Files changed (63) hide show
  1. package/README.md +117 -39
  2. package/dist/index.browser.cjs +64 -0
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.mjs +58 -1
  5. package/dist/index.browser.mjs.map +1 -1
  6. package/dist/index.native.mjs +58 -1
  7. package/dist/index.native.mjs.map +1 -1
  8. package/dist/index.node.cjs +64 -0
  9. package/dist/index.node.cjs.map +1 -1
  10. package/dist/index.node.mjs +58 -1
  11. package/dist/index.node.mjs.map +1 -1
  12. package/dist/query.browser.cjs +5 -52
  13. package/dist/query.browser.cjs.map +1 -1
  14. package/dist/query.browser.mjs +5 -52
  15. package/dist/query.browser.mjs.map +1 -1
  16. package/dist/query.native.mjs +5 -52
  17. package/dist/query.native.mjs.map +1 -1
  18. package/dist/query.node.cjs +5 -52
  19. package/dist/query.node.cjs.map +1 -1
  20. package/dist/query.node.mjs +5 -52
  21. package/dist/query.node.mjs.map +1 -1
  22. package/dist/types/index.d.ts +7 -0
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/dist/types/query/useSubscriptionQuery.d.ts +5 -5
  25. package/dist/types/query/useSubscriptionQuery.d.ts.map +1 -1
  26. package/dist/types/query/useTrackedDataQuery.d.ts +2 -2
  27. package/dist/types/query/useTrackedDataQuery.d.ts.map +1 -1
  28. package/dist/types/useAirdrop.d.ts +40 -0
  29. package/dist/types/useAirdrop.d.ts.map +1 -0
  30. package/dist/types/useClient.d.ts +7 -6
  31. package/dist/types/useClient.d.ts.map +1 -1
  32. package/dist/types/useIdentity.d.ts +28 -0
  33. package/dist/types/useIdentity.d.ts.map +1 -0
  34. package/dist/types/usePayer.d.ts +27 -0
  35. package/dist/types/usePayer.d.ts.map +1 -0
  36. package/dist/types/usePlanTransaction.d.ts +25 -0
  37. package/dist/types/usePlanTransaction.d.ts.map +1 -0
  38. package/dist/types/usePlanTransactions.d.ts +26 -0
  39. package/dist/types/usePlanTransactions.d.ts.map +1 -0
  40. package/dist/types/useSendTransaction.d.ts +29 -0
  41. package/dist/types/useSendTransaction.d.ts.map +1 -0
  42. package/dist/types/useSendTransactions.d.ts +28 -0
  43. package/dist/types/useSendTransactions.d.ts.map +1 -0
  44. package/package.json +10 -10
  45. package/src/index.ts +7 -0
  46. package/src/query/__tests__/useRequestQuery-test.browser.tsx +2 -2
  47. package/src/query/__tests__/useSubscriptionQuery-test.browser.tsx +7 -9
  48. package/src/query/__tests__/useTrackedDataQuery-test.browser.tsx +3 -3
  49. package/src/query/useSubscriptionQuery.ts +9 -7
  50. package/src/query/useTrackedDataQuery.ts +9 -4
  51. package/src/swr/__tests__/useRequestSWR-test.browser.tsx +4 -6
  52. package/src/useAirdrop.ts +45 -0
  53. package/src/useClient.ts +7 -6
  54. package/src/useIdentity.ts +47 -0
  55. package/src/usePayer.ts +44 -0
  56. package/src/usePlanTransaction.ts +30 -0
  57. package/src/usePlanTransactions.ts +31 -0
  58. package/src/useSendTransaction.ts +34 -0
  59. package/src/useSendTransactions.ts +33 -0
  60. package/dist/types/query/bridgeStoreToAsyncIterable.d.ts +0 -39
  61. package/dist/types/query/bridgeStoreToAsyncIterable.d.ts.map +0 -1
  62. package/src/query/__tests__/bridgeStoreToAsyncIterable-test.ts +0 -188
  63. package/src/query/bridgeStoreToAsyncIterable.ts +0 -105
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/query/useRequestQuery.ts","../src/query/bridgeStoreToAsyncIterable.ts","../src/query/useSubscriptionQuery.ts","../src/query/useTrackedDataQuery.ts"],"names":["useCallback","useQuery","experimental_streamedQuery"],"mappings":"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","file":"query.node.mjs","sourcesContent":["import type { ReactiveActionSource } from '@solana/kit';\nimport {\n type QueryFunctionContext,\n type QueryKey,\n useQuery,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\nimport { useLatest } from '../useLatest';\nimport type { UseRequestOptions } from '../useRequest';\n\n/**\n * Options accepted by {@link useRequestQuery}: every option `@tanstack/react-query`'s `useQuery`\n * takes (minus `queryKey` and `queryFn`, which this hook owns) plus the Kit-specific\n * {@link UseRequestOptions}.\n *\n * @typeParam T - The value the underlying request resolves to.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied.\n */\nexport type UseRequestQueryOptions<T, TError = unknown, TData = T> = Omit<\n UseQueryOptions<T, TError, TData, QueryKey>,\n 'queryFn' | 'queryKey'\n> &\n UseRequestOptions;\n\n/**\n * TanStack Query-backed counterpart to core's `useRequest`. Accepts the same source shape — a\n * {@link ReactiveActionSource} (satisfied by `PendingRpcRequest<T>`) or a\n * `(signal: AbortSignal) => Promise<T>` function — and routes it through TanStack Query's cache, so\n * components reading the same `key` dedupe into one in-flight request and the result becomes\n * Suspense-capable and visible in TanStack Query's devtools.\n *\n * The query's `queryFn` is handed TanStack Query's own `AbortSignal`, which aborts when the query\n * is cancelled (unmount, garbage collection, or a superseding refetch). That signal is threaded\n * into the source so cancellation propagates all the way down. When a `getAbortSignal` factory is\n * also supplied (e.g. for a per-attempt timeout), the two signals are combined via\n * {@link AbortSignal.any} — aborting either one cancels the attempt.\n *\n * Pass `null` for `source` to disable — useful when one of the source's inputs isn't yet known.\n * This maps to TanStack's `enabled: false` and combines with any `enabled` you pass yourself (the\n * query runs only when the source is non-null *and* your `enabled` is not `false`). Use\n * `result.refetch()` to refresh.\n *\n * @typeParam T - The value the underlying request resolves to.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied; pass a `select: (data: T) => TData` option to project the cached value into\n * a different shape and `result.data` narrows accordingly.\n *\n * @example\n * ```tsx\n * function LatestBlockhash() {\n * const client = useClient<ClientWithRpc<GetLatestBlockhashApi>>();\n * const { data, error, isLoading, refetch } = useRequestQuery(\n * ['latestBlockhash'],\n * client.rpc.getLatestBlockhash(),\n * { getAbortSignal: () => AbortSignal.timeout(5_000) },\n * );\n * if (error) return <button onClick={() => refetch()}>Retry</button>;\n * if (isLoading) return <p>Loading…</p>;\n * return <p>Blockhash: {data!.value.blockhash}</p>;\n * }\n *\n * // Function shape — wraps an arbitrary async call. The source can be an inline closure recreated\n * // each render; the hook reads the latest one when the query fires and keys the cache off `key`,\n * // so there's no need to memoize it.\n * function Profile({ userId }: { userId: string }) {\n * const { data, error, isLoading, refetch } = useRequestQuery(\n * ['users', userId],\n * (signal: AbortSignal) => fetch(`/api/users/${userId}`, { signal }).then(r => r.json()),\n * );\n * if (error) return <button onClick={() => refetch()}>Retry</button>;\n * if (isLoading) return <p>Loading…</p>;\n * return <p>{data!.name}</p>;\n * }\n * ```\n *\n * @see {@link UseRequestQueryOptions}\n */\nexport function useRequestQuery<T, TError = unknown, TData = T>(\n key: QueryKey,\n source: ReactiveActionSource<T> | ((signal: AbortSignal) => Promise<T>) | null,\n options?: UseRequestQueryOptions<T, TError, TData>,\n): UseQueryResult<TData, TError> {\n // Split our option off the TanStack config so we can hand the rest to `useQuery` cleanly.\n const { getAbortSignal, ...queryOptions } = options ?? {};\n\n // Ref-sync the source and the abort-signal factory so an inline closure passed each render\n // doesn't change the queryFn's identity. The queryFn reads the latest values from the refs when\n // it fires; TanStack uses the key (not the queryFn identity) for cache lookup.\n const sourceRef = useLatest(source);\n const getAbortSignalRef = useLatest(getAbortSignal);\n\n const queryFn = useCallback(\n async ({ signal }: QueryFunctionContext): Promise<T> => {\n const current = sourceRef.current;\n if (current == null) {\n // Defensive: a null source forces `enabled: false` below, so TanStack won't schedule\n // this queryFn. This branch should be unreachable.\n throw new Error('useRequestQuery: the queryFn ran with a null source');\n }\n const userSignal = getAbortSignalRef.current?.();\n // `signal` is TanStack's query-cancellation signal. Combine it with the caller's signal\n // (when present) so aborting either cancels the attempt.\n const combinedSignal = userSignal ? AbortSignal.any([signal, userSignal]) : signal;\n if (typeof current === 'function') {\n return await current(combinedSignal);\n }\n return await current.reactiveStore().withSignal(combinedSignal).dispatchAsync();\n // `sourceRef` and `getAbortSignalRef` are stable refs from `useLatest`, so listing them\n // leaves `queryFn` referentially stable across renders — TanStack keys off `key`, not\n // the queryFn identity, but a stable queryFn avoids needless churn.\n },\n [getAbortSignalRef, sourceRef],\n );\n\n return useQuery<T, TError, TData, QueryKey>({\n ...queryOptions,\n // A null source disables the query (TanStack's `enabled: false`). Combine with the caller's\n // own `enabled` so the query runs only when the source is present *and* the caller hasn't\n // disabled it.\n enabled: source != null && (queryOptions.enabled ?? true),\n queryFn,\n queryKey: key,\n });\n}\n","import {\n type ReactiveStreamStore,\n SOLANA_ERROR__REACT__SUBSCRIPTION_CLOSED_WITHOUT_ERROR,\n SolanaError,\n} from '@solana/kit';\n\n/**\n * Bridges a {@link ReactiveStreamStore} into the `AsyncIterable` contract that TanStack Query's\n * `experimental_streamedQuery` consumes. The TanStack twin of `bridgeStoreToSwr`: where the SWR\n * bridge pushes each store update into a `next` callback, this one exposes a *pull*-based async\n * iterable, since `streamedQuery` drives the stream by `for await`-ing it.\n *\n * Subscribes to the store, `connect()`s it bound to `signal`, and yields its unified lifecycle:\n * - `loaded` → yields the value, unless an optional `shouldYield` predicate rejects it. Latest-wins:\n * if several notifications land between pulls, only the most recent unconsumed value is yielded (a\n * subscription consumer wants the freshest state, not a backlog).\n * - `error` → throws, so the `streamedQuery` queryFn rejects and the query surfaces `error`.\n * Substitutes a {@link SOLANA_ERROR__REACT__SUBSCRIPTION_CLOSED_WITHOUT_ERROR} sentinel when the\n * store reports an error with a nullish payload (mirrors `bridgeStoreToSwr`). An error takes\n * precedence over a buffered value: if a `loaded` value is still pending when an `error` arrives,\n * that value is dropped and the error propagates (once errored, stop yielding).\n * - `signal` aborts → ends the iterable cleanly (no error). An abort means teardown — unmount, a\n * superseding refetch, or a caller-supplied deadline — so the subscription stops rather than\n * failing.\n *\n * Whichever way the iterable ends — value exhaustion, error, or abort — the `finally` block\n * unsubscribes and `reset()`s the store, aborting the active connection. The store the caller hands\n * in is owned by this bridge for the iterable's lifetime.\n *\n * @typeParam T - The notification type emitted by the store.\n *\n * @param store - An idle stream store to drive.\n * @param signal - The abort signal to bind the connection to (TanStack's query-cancellation signal,\n * optionally combined with a caller-supplied one). Aborting it tears the stream down.\n * @param shouldYield - Optional gate run against each `loaded` value before it is yielded. Return\n * `false` to drop the value. When omitted, every loaded value is yielded.\n *\n * @returns An `AsyncIterable<T>` that yields each store value until the store errors or `signal`\n * aborts.\n *\n * @internal\n */\nexport function bridgeStoreToAsyncIterable<T>(\n store: ReactiveStreamStore<T>,\n signal: AbortSignal,\n shouldYield?: (value: T) => boolean,\n): AsyncIterable<T> {\n return {\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n // Latest-wins single-slot buffer plus a one-shot \"something changed\" deferred the loop\n // parks on. `wake()` resolves the current deferred and arms a fresh one for the next park.\n let latest: { readonly value: T } | undefined;\n let failure: { readonly error: unknown } | undefined;\n let deferred = Promise.withResolvers<void>();\n const wake = () => {\n const { resolve } = deferred;\n deferred = Promise.withResolvers<void>();\n resolve();\n };\n\n const onChange = () => {\n const state = store.getState();\n if (state.status === 'loaded') {\n // Drop a value the gate rejects. The stream parks again rather than yielding it.\n if (shouldYield && !shouldYield(state.data)) return;\n latest = { value: state.data };\n wake();\n } else if (state.status === 'error') {\n // A nullish error would otherwise surface as a value-less success; substitute a\n // sentinel so the failure propagates, matching `bridgeStoreToSwr`.\n failure = {\n error: state.error ?? new SolanaError(SOLANA_ERROR__REACT__SUBSCRIPTION_CLOSED_WITHOUT_ERROR),\n };\n wake();\n }\n // `idle` / `loading` carry no value and no error — nothing to yield.\n };\n\n const onAbort = () => wake();\n signal.addEventListener('abort', onAbort, { once: true });\n const unsubscribe = store.subscribe(onChange);\n // Bind the connection to `signal` so an abort tears down the underlying stream too.\n store.withSignal(signal).connect();\n try {\n while (true) {\n // Abort wins over everything: an abort is teardown, so end cleanly without\n // surfacing the store's incidental abort-driven error state.\n if (signal.aborted) return;\n if (failure) throw failure.error;\n if (latest) {\n const { value } = latest;\n latest = undefined;\n yield value;\n continue;\n }\n await deferred.promise;\n }\n } finally {\n signal.removeEventListener('abort', onAbort);\n unsubscribe();\n store.reset();\n }\n },\n };\n}\n","import type { ReactiveStreamSource } from '@solana/kit';\nimport {\n experimental_streamedQuery,\n type QueryFunction,\n type QueryFunctionContext,\n type QueryKey,\n useQuery,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\nimport { useLatest } from '../useLatest';\nimport type { UseRequestOptions } from '../useRequest';\nimport { bridgeStoreToAsyncIterable } from './bridgeStoreToAsyncIterable';\n\n/**\n * Options accepted by {@link useSubscriptionQuery}: every option `@tanstack/react-query`'s `useQuery`\n * takes (minus `queryKey` and `queryFn`, which this hook owns) plus the Kit-specific\n * {@link UseRequestOptions}.\n *\n * @typeParam T - The notification type emitted by the source.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied.\n */\nexport type UseSubscriptionQueryOptions<T, TError = unknown, TData = T> = Omit<\n UseQueryOptions<T, TError, TData, QueryKey>,\n 'queryFn' | 'queryKey'\n> &\n UseRequestOptions;\n\n/**\n * TanStack Query-backed counterpart to core's `useSubscription`, for streams that have no one-shot\n * RPC fetch counterpart. Routes a long-lived stream through TanStack Query's cache via\n * `experimental_streamedQuery`, so components reading the same `key` share one underlying connection\n * and the stream participates in TanStack Query's cache and devtools.\n *\n * The source has the same two shapes as {@link useRequestQuery}, the pull-based analog of its\n * `(signal) => Promise<T>` arm: a {@link ReactiveStreamSource} (satisfied by an RPC subscription) or\n * a raw `(signal: AbortSignal) => AsyncIterable<T>` factory. `streamedQuery` is itself built on\n * `AsyncIterable`, so the factory's iterable is consumed directly; a `ReactiveStreamSource` is\n * adapted to one internally. The factory receives TanStack's query-cancellation signal (combined\n * with any `getAbortSignal` you supply) so a `fetch`- or socket-backed generator can bind\n * cancellation to it.\n *\n * `data` is the raw notification, exactly as the source emits it. For RPC subscriptions read\n * `data.value` and `data.context.slot` yourself.\n *\n * Because the stream never settles, the query stays in `fetchStatus: 'fetching'` for the\n * subscription's whole life — `isFetching` is permanently `true` and `isLoading` flips false\n * after the first notification. Read `data` / `error` / `status` and ignore `isFetching` for\n * subscriptions. `result.refetch()` reconnects: TanStack aborts the old signal (ending the prior\n * iterable, which resets its store) and opens a fresh stream. Fire and forget — for a never-ending\n * stream the returned promise never resolves, so don't `await refetch()` (a click handler that does\n * will hang forever).\n *\n * Defaults, all overridable: `retry: false` (the underlying reactive store owns retry/backoff),\n * `staleTime: Infinity` and `refetchOnWindowFocus: false` (a focus revalidation must not tear down\n * and re-open the socket — the subscription is what keeps data fresh). The internal `refetchMode` is\n * `'append'` paired with a replace-latest reducer: every notification is written to the cache live,\n * and the prior value stays visible across a reconnect (stale-while-revalidate).\n *\n * Pass `null` for `source` to disable — maps to TanStack's `enabled: false` and combines with any\n * `enabled` you pass (the query runs only when the source is non-null *and* your `enabled` is not\n * `false`).\n *\n * @typeParam T - The notification type emitted by the source.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied; pass a `select: (data: T) => TData` option to project each notification into\n * a different shape and `result.data` narrows accordingly.\n *\n * @example\n * ```tsx\n * function SlotHeight() {\n * const client = useClient<ClientWithRpcSubscriptions<SlotNotificationsApi>>();\n * const { data, error } = useSubscriptionQuery(['slot'], client.rpcSubscriptions.slotNotifications());\n * if (error) return <p>Disconnected.</p>;\n * if (!data) return <p>Connecting…</p>;\n * return <p>Slot {String(data.slot)}</p>;\n * }\n *\n * // Function shape — wraps an arbitrary async iterable, threading the cancellation signal in.\n * function Ticker() {\n * const { data } = useSubscriptionQuery(['ticker'], (signal: AbortSignal) => streamPrices(signal));\n * return <p>{data ?? '…'}</p>;\n * }\n * ```\n *\n * @see {@link UseSubscriptionQueryOptions}\n * @see {@link useRequestQuery}\n */\nexport function useSubscriptionQuery<T, TError = unknown, TData = T>(\n key: QueryKey,\n source: ReactiveStreamSource<T> | ((signal: AbortSignal) => AsyncIterable<T>) | null,\n options?: UseSubscriptionQueryOptions<T, TError, TData>,\n): UseQueryResult<TData, TError> {\n // Split our option off the TanStack config so we can hand the rest to `useQuery` cleanly.\n const { getAbortSignal, ...queryOptions } = options ?? {};\n\n // Ref-sync the source and the abort-signal factory so an inline value passed each render doesn't\n // change the streamFn's identity. The streamFn reads the latest values from the refs when it\n // fires; TanStack uses the key (not the queryFn identity) for cache lookup.\n const sourceRef = useLatest(source);\n const getAbortSignalRef = useLatest(getAbortSignal);\n\n const queryFn = useCallback<QueryFunction<T, QueryKey>>(\n context =>\n // `streamedQuery`'s generics default to array accumulation (`TData = Array<TQueryFnData>`).\n // The explicit `<T, T>` plus a replace-latest reducer types the cache value as the latest\n // scalar notification rather than `T[]`. `initialValue` only seeds the (ignored) reducer\n // accumulator before the first chunk, so its value is irrelevant — only its type matters.\n experimental_streamedQuery<T, T>({\n initialValue: undefined as T,\n reducer: (_previous, chunk) => chunk,\n // `'append'` is the only mode that writes every chunk to the cache live while leaving\n // the prior value in place across a refetch. `'reset'` would flash to pending on each\n // reconnect; `'replace'` only flushes once at stream end — which for a never-ending\n // subscription never happens (an abort skips the final write), freezing the value.\n refetchMode: 'append',\n streamFn: ({ signal }: QueryFunctionContext) => {\n const current = sourceRef.current;\n if (current == null) {\n // Defensive: a null source forces `enabled: false` below, so TanStack won't\n // schedule this queryFn. This branch should be unreachable.\n throw new Error('useSubscriptionQuery: the streamFn ran with a null source');\n }\n const userSignal = getAbortSignalRef.current?.();\n // `signal` is TanStack's query-cancellation signal. Combine it with the caller's\n // signal (when present) so aborting either tears the stream down.\n const combinedSignal = userSignal ? AbortSignal.any([signal, userSignal]) : signal;\n if (typeof current === 'function') {\n return current(combinedSignal);\n }\n return bridgeStoreToAsyncIterable(current.reactiveStore(), combinedSignal);\n },\n })(context),\n [getAbortSignalRef, sourceRef],\n );\n\n return useQuery<T, TError, TData, QueryKey>({\n // Sensible defaults for a long-lived stream; all overridable by `queryOptions` below.\n refetchOnWindowFocus: false,\n retry: false,\n staleTime: Infinity,\n ...queryOptions,\n // A null source disables the query (TanStack's `enabled: false`). Combine with the caller's\n // own `enabled` so the query runs only when the source is present *and* not disabled.\n enabled: source != null && (queryOptions.enabled ?? true),\n queryFn,\n queryKey: key,\n });\n}\n","import { createReactiveStoreWithInitialValueAndSlotTracking, type SolanaRpcResponse } from '@solana/kit';\nimport {\n experimental_streamedQuery,\n type QueryFunction,\n type QueryFunctionContext,\n type QueryKey,\n useQuery,\n useQueryClient,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\nimport { useLatest } from '../useLatest';\nimport type { UseRequestOptions } from '../useRequest';\nimport type { TrackedDataSpec } from '../useTrackedData';\nimport { bridgeStoreToAsyncIterable } from './bridgeStoreToAsyncIterable';\n\n/**\n * Options accepted by {@link useTrackedDataQuery}: every option `@tanstack/react-query`'s `useQuery`\n * takes (minus `queryKey` and `queryFn`, which this hook owns) plus the Kit-specific\n * {@link UseRequestOptions}.\n *\n * @typeParam TItem - The unified item type produced by the spec's two mappers, surfaced as\n * `data.value`.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to the\n * `SolanaRpcResponse<TItem>` envelope when no `select` is supplied.\n */\nexport type UseTrackedDataQueryOptions<TItem, TError = unknown, TData = SolanaRpcResponse<TItem>> = Omit<\n UseQueryOptions<SolanaRpcResponse<TItem>, TError, TData, QueryKey>,\n 'queryFn' | 'queryKey'\n> &\n UseRequestOptions;\n\n/**\n * TanStack Query-backed counterpart to core's `useTrackedData`. Pairs a one-shot RPC fetch with an\n * ongoing subscription (slot-deduped by the underlying Kit primitive) and routes the unified stream\n * through TanStack Query's cache via `experimental_streamedQuery`, so components reading the same\n * `key` share one underlying connection and the stream participates in TanStack Query's cache and\n * devtools.\n *\n * `data` is the `SolanaRpcResponse<TItem>` envelope emitted by the underlying kit primitive — the\n * primitive's type guarantees the envelope shape, so callers can read `data.value` (the unified item\n * produced by the spec's mappers) and `data.context.slot` (the slot the store dedup'd on) directly.\n *\n * Pass a {@link TrackedDataSpec} keyed on whatever inputs it depends on; the hook reads the latest\n * one from a ref, so an inline spec recreated each render is fine (TanStack keys the cache off `key`,\n * not the spec identity — bump the `key` to swap specs). Pass `null` for `spec` to disable — maps to\n * TanStack's `enabled: false` and combines with any `enabled` you pass (the query runs only when the\n * spec is non-null *and* your `enabled` is not `false`).\n *\n * Because the subscription never settles, the query stays in `fetchStatus: 'fetching'` for its whole\n * life — `isFetching` is permanently `true` and `isLoading` flips false after the first value. Read\n * `data` / `error` / `status` and ignore `isFetching`. `result.refetch()` reconnects: TanStack aborts\n * the old signal (ending the prior iterable, which resets its store) and re-runs both the initial RPC\n * fetch and the subscription. Fire and forget — for a never-ending stream the returned promise never\n * resolves, so don't `await refetch()`.\n *\n * Defaults, all overridable: `retry: false` (the underlying reactive store owns retry/backoff),\n * `staleTime: Infinity` and `refetchOnWindowFocus: false` (a focus revalidation must not tear down\n * and re-open the socket — the subscription is what keeps data fresh). The internal `refetchMode` is\n * `'append'` paired with a replace-latest reducer: every value is written to the cache live, and the\n * prior value stays visible across a reconnect (stale-while-revalidate).\n *\n * Slot dedupe spans the TanStack cache, not just one store. The underlying primitive tracks a slot\n * high-water mark per store, but that mark dies when the store is disposed while the cache entry\n * survives. `refetch()` mints a fresh store (high-water reset to -1) while `refetchMode: 'append'`\n * keeps the prior envelope cached, so this hook bridges that gap: the reconnect's fresh store cannot\n * regress the cached envelope to an older slot — e.g. a lagging RPC node resolving the new initial\n * fetch behind the cached value is refused, and the warmer cached value stands until something newer\n * arrives.\n *\n * @typeParam TInitialValue - The value inside the initial RPC `SolanaRpcResponse` envelope.\n * @typeParam TStreamValue - The value inside subscription `SolanaRpcResponse` notifications.\n * @typeParam TItem - The unified item type produced by the two mappers, surfaced as `data.value`.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to the\n * `SolanaRpcResponse<TItem>` envelope when no `select` is supplied; pass a\n * `select: (data: SolanaRpcResponse<TItem>) => TData` option to project each value into a different\n * shape and `result.data` narrows accordingly.\n *\n * @example\n * ```tsx\n * function AccountBalance({ address }: { address: Address }) {\n * const client = useClient<ClientWithRpc<GetBalanceApi> & ClientWithRpcSubscriptions<AccountNotificationsApi>>();\n * const spec = useMemo(() => ({\n * initialValueSource: client.rpc.getBalance(address),\n * initialValueMapper: (lamports: bigint) => lamports,\n * streamSource: client.rpcSubscriptions.accountNotifications(address),\n * streamValueMapper: ({ lamports }: { lamports: bigint }) => lamports,\n * }), [client, address]);\n * const { data, error } = useTrackedDataQuery(['balance', address], spec);\n * if (error) return <p>Failed to load.</p>;\n * return <p>{data ? `${data.value} lamports at slot ${data.context.slot}` : 'Loading…'}</p>;\n * }\n * ```\n *\n * @see {@link UseTrackedDataQueryOptions}\n * @see {@link useSubscriptionQuery}\n */\nexport function useTrackedDataQuery<\n TInitialValue,\n TStreamValue,\n TItem,\n TError = unknown,\n TData = SolanaRpcResponse<TItem>,\n>(\n key: QueryKey,\n spec: TrackedDataSpec<TInitialValue, TStreamValue, TItem> | null,\n options?: UseTrackedDataQueryOptions<TItem, TError, TData>,\n): UseQueryResult<TData, TError> {\n // Split our option off the TanStack config so we can hand the rest to `useQuery` cleanly.\n const { getAbortSignal, ...queryOptions } = options ?? {};\n\n // Ref-sync the spec and the abort-signal factory so an inline value passed each render doesn't\n // change the streamFn's identity. The streamFn reads the latest values from the refs when it\n // fires; TanStack uses the key (not the queryFn identity) for cache lookup.\n const specRef = useLatest(spec);\n const getAbortSignalRef = useLatest(getAbortSignal);\n\n // The cache outlives the per-attempt store, but the store's slot high-water mark does not — a\n // fresh store (remount, refetch) starts its window at -1. The streamFn reads the currently\n // cached envelope through this client to refuse any value older than what the cache already\n // holds. `useQueryClient` returns a stable reference, so listing it in the deps below is churn-free.\n const queryClient = useQueryClient();\n\n const queryFn = useCallback<QueryFunction<SolanaRpcResponse<TItem>, QueryKey>>(\n context =>\n // `streamedQuery`'s generics default to array accumulation (`TData = Array<TQueryFnData>`).\n // The explicit `<Envelope, Envelope>` plus a replace-latest reducer types the cache value\n // as the latest scalar envelope rather than an array. `initialValue` only seeds the\n // (ignored) reducer accumulator before the first chunk, so its value is irrelevant — only\n // its type matters.\n experimental_streamedQuery<SolanaRpcResponse<TItem>, SolanaRpcResponse<TItem>>({\n initialValue: undefined as unknown as SolanaRpcResponse<TItem>,\n reducer: (_previous, chunk) => chunk,\n // `'append'` is the only mode that writes every chunk to the cache live while leaving\n // the prior value in place across a refetch. `'reset'` would flash to pending on each\n // reconnect; `'replace'` only flushes once at stream end — which for a never-ending\n // subscription never happens (an abort skips the final write), freezing the value.\n refetchMode: 'append',\n streamFn: ({ queryKey, signal }: QueryFunctionContext) => {\n const current = specRef.current;\n if (current == null) {\n // Defensive: a null spec forces `enabled: false` below, so TanStack won't\n // schedule this queryFn. This branch should be unreachable.\n throw new Error('useTrackedDataQuery: the streamFn ran with a null spec');\n }\n const userSignal = getAbortSignalRef.current?.();\n // `signal` is TanStack's query-cancellation signal. Combine it with the caller's\n // signal (when present) so aborting either tears the stream down.\n const combinedSignal = userSignal ? AbortSignal.any([signal, userSignal]) : signal;\n const store = createReactiveStoreWithInitialValueAndSlotTracking(current);\n // Refuse any envelope older than the slot the cache already holds. A fresh store\n // (e.g. after a remount) tracks slots from scratch, so without this it could\n // overwrite the cached value with an older one from a lagging RPC node.\n return bridgeStoreToAsyncIterable(store, combinedSignal, value => {\n const cachedSlot =\n queryClient.getQueryData<SolanaRpcResponse<TItem>>(queryKey)?.context.slot ?? -1n;\n return value.context.slot > cachedSlot;\n });\n },\n })(context),\n [getAbortSignalRef, queryClient, specRef],\n );\n\n return useQuery<SolanaRpcResponse<TItem>, TError, TData, QueryKey>({\n // Sensible defaults for a long-lived stream; all overridable by `queryOptions` below.\n refetchOnWindowFocus: false,\n retry: false,\n staleTime: Infinity,\n ...queryOptions,\n // A null spec disables the query (TanStack's `enabled: false`). Combine with the caller's own\n // `enabled` so the query runs only when the spec is present *and* not disabled.\n enabled: spec != null && (queryOptions.enabled ?? true),\n queryFn,\n queryKey: key,\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/query/useRequestQuery.ts","../src/query/useSubscriptionQuery.ts","../src/query/useTrackedDataQuery.ts"],"names":["useCallback","useQuery","experimental_streamedQuery","bridgeStoreToAsyncIterable"],"mappings":";;;;;AAmFO,SAAS,eAAA,CACZ,GAAA,EACA,MAAA,EACA,OAAA,EAC6B;AAE7B,EAAA,MAAM,EAAE,cAAA,EAAgB,GAAG,YAAA,EAAa,GAAI,WAAW,EAAC;AAKxD,EAAA,MAAM,SAAA,GAAY,UAAU,MAAM,CAAA;AAClC,EAAA,MAAM,iBAAA,GAAoB,UAAU,cAAc,CAAA;AAElD,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACZ,OAAO,EAAE,MAAA,EAAO,KAAwC;AACpD,MAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,MAAA,IAAI,WAAW,IAAA,EAAM;AAGjB,QAAA,MAAM,IAAI,MAAM,qDAAqD,CAAA;AAAA,MACzE;AACA,MAAA,MAAM,UAAA,GAAa,kBAAkB,OAAA,IAAU;AAG/C,MAAA,MAAM,cAAA,GAAiB,aAAa,WAAA,CAAY,GAAA,CAAI,CAAC,MAAA,EAAQ,UAAU,CAAC,CAAA,GAAI,MAAA;AAC5E,MAAA,IAAI,OAAO,YAAY,UAAA,EAAY;AAC/B,QAAA,OAAO,MAAM,QAAQ,cAAc,CAAA;AAAA,MACvC;AACA,MAAA,OAAO,MAAM,OAAA,CAAQ,aAAA,GAAgB,UAAA,CAAW,cAAc,EAAE,aAAA,EAAc;AAAA,IAIlF,CAAA;AAAA,IACA,CAAC,mBAAmB,SAAS;AAAA,GACjC;AAEA,EAAA,OAAO,QAAA,CAAqC;AAAA,IACxC,GAAG,YAAA;AAAA;AAAA;AAAA;AAAA,IAIH,OAAA,EAAS,MAAA,IAAU,IAAA,KAAS,YAAA,CAAa,OAAA,IAAW,IAAA,CAAA;AAAA,IACpD,OAAA;AAAA,IACA,QAAA,EAAU;AAAA,GACb,CAAA;AACL;ACrCO,SAAS,oBAAA,CACZ,GAAA,EACA,MAAA,EACA,OAAA,EAC6B;AAE7B,EAAA,MAAM,EAAE,cAAA,EAAgB,GAAG,YAAA,EAAa,GAAI,WAAW,EAAC;AAKxD,EAAA,MAAM,SAAA,GAAY,UAAU,MAAM,CAAA;AAClC,EAAA,MAAM,iBAAA,GAAoB,UAAU,cAAc,CAAA;AAElD,EAAA,MAAM,OAAA,GAAUA,WAAAA;AAAA,IACZ,CAAA,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKI,0BAAA,CAAiC;AAAA,QAC7B,YAAA,EAAc,MAAA;AAAA,QACd,OAAA,EAAS,CAAC,SAAA,EAAW,KAAA,KAAU,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAK/B,WAAA,EAAa,QAAA;AAAA,QACb,QAAA,EAAU,CAAC,EAAE,MAAA,EAAO,KAA4B;AAC5C,UAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,UAAA,IAAI,WAAW,IAAA,EAAM;AAGjB,YAAA,MAAM,IAAI,MAAM,2DAA2D,CAAA;AAAA,UAC/E;AACA,UAAA,MAAM,UAAA,GAAa,kBAAkB,OAAA,IAAU;AAG/C,UAAA,MAAM,cAAA,GAAiB,aAAa,WAAA,CAAY,GAAA,CAAI,CAAC,MAAA,EAAQ,UAAU,CAAC,CAAA,GAAI,MAAA;AAC5E,UAAA,IAAI,OAAO,YAAY,UAAA,EAAY;AAC/B,YAAA,OAAO,QAAQ,cAAc,CAAA;AAAA,UACjC;AACA,UAAA,MAAM,KAAA,GAAQ,QAAQ,aAAA,EAAc;AAEpC,UAAA,KAAA,CAAM,UAAA,CAAW,cAAc,CAAA,CAAE,OAAA,EAAQ;AACzC,UAAA,OAAO,0BAAA,CAA2B,OAAO,cAAc,CAAA;AAAA,QAC3D;AAAA,OACH,EAAE,OAAO;AAAA,KAAA;AAAA,IACd,CAAC,mBAAmB,SAAS;AAAA,GACjC;AAEA,EAAA,OAAOC,QAAAA,CAAqC;AAAA;AAAA,IAExC,oBAAA,EAAsB,KAAA;AAAA,IACtB,KAAA,EAAO,KAAA;AAAA,IACP,SAAA,EAAW,QAAA;AAAA,IACX,GAAG,YAAA;AAAA;AAAA;AAAA,IAGH,OAAA,EAAS,MAAA,IAAU,IAAA,KAAS,YAAA,CAAa,OAAA,IAAW,IAAA,CAAA;AAAA,IACpD,OAAA;AAAA,IACA,QAAA,EAAU;AAAA,GACb,CAAA;AACL;ACnDO,SAAS,mBAAA,CAOZ,GAAA,EACA,IAAA,EACA,OAAA,EAC6B;AAE7B,EAAA,MAAM,EAAE,cAAA,EAAgB,GAAG,YAAA,EAAa,GAAI,WAAW,EAAC;AAKxD,EAAA,MAAM,OAAA,GAAU,UAAU,IAAI,CAAA;AAC9B,EAAA,MAAM,iBAAA,GAAoB,UAAU,cAAc,CAAA;AAMlD,EAAA,MAAM,cAAc,cAAA,EAAe;AAEnC,EAAA,MAAM,OAAA,GAAUD,WAAAA;AAAA,IACZ,CAAA,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMIE,0BAAAA,CAA+E;AAAA,QAC3E,YAAA,EAAc,MAAA;AAAA,QACd,OAAA,EAAS,CAAC,SAAA,EAAW,KAAA,KAAU,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAK/B,WAAA,EAAa,QAAA;AAAA,QACb,QAAA,EAAU,CAAC,EAAE,QAAA,EAAU,QAAO,KAA4B;AACtD,UAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,UAAA,IAAI,WAAW,IAAA,EAAM;AAGjB,YAAA,MAAM,IAAI,MAAM,wDAAwD,CAAA;AAAA,UAC5E;AACA,UAAA,MAAM,UAAA,GAAa,kBAAkB,OAAA,IAAU;AAG/C,UAAA,MAAM,cAAA,GAAiB,aAAa,WAAA,CAAY,GAAA,CAAI,CAAC,MAAA,EAAQ,UAAU,CAAC,CAAA,GAAI,MAAA;AAC5E,UAAA,MAAM,KAAA,GAAQ,mDAAmD,OAAO,CAAA;AAExE,UAAA,KAAA,CAAM,UAAA,CAAW,cAAc,CAAA,CAAE,OAAA,EAAQ;AAIzC,UAAA,OAAOC,0BAAAA,CAA2B,KAAA,EAAO,cAAA,EAAgB,CAAA,KAAA,KAAS;AAC9D,YAAA,MAAM,aACF,WAAA,CAAY,YAAA,CAAuC,QAAQ,CAAA,EAAG,OAAA,CAAQ,QAAQ,CAAC,EAAA;AACnF,YAAA,OAAO,KAAA,CAAM,QAAQ,IAAA,GAAO,UAAA;AAAA,UAChC,CAAC,CAAA;AAAA,QACL;AAAA,OACH,EAAE,OAAO;AAAA,KAAA;AAAA,IACd,CAAC,iBAAA,EAAmB,WAAA,EAAa,OAAO;AAAA,GAC5C;AAEA,EAAA,OAAOF,QAAAA,CAA4D;AAAA;AAAA,IAE/D,oBAAA,EAAsB,KAAA;AAAA,IACtB,KAAA,EAAO,KAAA;AAAA,IACP,SAAA,EAAW,QAAA;AAAA,IACX,GAAG,YAAA;AAAA;AAAA;AAAA,IAGH,OAAA,EAAS,IAAA,IAAQ,IAAA,KAAS,YAAA,CAAa,OAAA,IAAW,IAAA,CAAA;AAAA,IAClD,OAAA;AAAA,IACA,QAAA,EAAU;AAAA,GACb,CAAA;AACL","file":"query.node.mjs","sourcesContent":["import type { ReactiveActionSource } from '@solana/kit';\nimport {\n type QueryFunctionContext,\n type QueryKey,\n useQuery,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\nimport { useLatest } from '../useLatest';\nimport type { UseRequestOptions } from '../useRequest';\n\n/**\n * Options accepted by {@link useRequestQuery}: every option `@tanstack/react-query`'s `useQuery`\n * takes (minus `queryKey` and `queryFn`, which this hook owns) plus the Kit-specific\n * {@link UseRequestOptions}.\n *\n * @typeParam T - The value the underlying request resolves to.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied.\n */\nexport type UseRequestQueryOptions<T, TError = unknown, TData = T> = Omit<\n UseQueryOptions<T, TError, TData, QueryKey>,\n 'queryFn' | 'queryKey'\n> &\n UseRequestOptions;\n\n/**\n * TanStack Query-backed counterpart to core's `useRequest`. Accepts the same source shape — a\n * {@link ReactiveActionSource} (satisfied by `PendingRpcRequest<T>`) or a\n * `(signal: AbortSignal) => Promise<T>` function — and routes it through TanStack Query's cache, so\n * components reading the same `key` dedupe into one in-flight request and the result becomes\n * Suspense-capable and visible in TanStack Query's devtools.\n *\n * The query's `queryFn` is handed TanStack Query's own `AbortSignal`, which aborts when the query\n * is cancelled (unmount, garbage collection, or a superseding refetch). That signal is threaded\n * into the source so cancellation propagates all the way down. When a `getAbortSignal` factory is\n * also supplied (e.g. for a per-attempt timeout), the two signals are combined via\n * {@link AbortSignal.any} — aborting either one cancels the attempt.\n *\n * Pass `null` for `source` to disable — useful when one of the source's inputs isn't yet known.\n * This maps to TanStack's `enabled: false` and combines with any `enabled` you pass yourself (the\n * query runs only when the source is non-null *and* your `enabled` is not `false`). Use\n * `result.refetch()` to refresh.\n *\n * @typeParam T - The value the underlying request resolves to.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied; pass a `select: (data: T) => TData` option to project the cached value into\n * a different shape and `result.data` narrows accordingly.\n *\n * @example\n * ```tsx\n * function LatestBlockhash() {\n * const client = useClient<ClientWithRpc<GetLatestBlockhashApi>>();\n * const { data, error, isLoading, refetch } = useRequestQuery(\n * ['latestBlockhash'],\n * client.rpc.getLatestBlockhash(),\n * { getAbortSignal: () => AbortSignal.timeout(5_000) },\n * );\n * if (error) return <button onClick={() => refetch()}>Retry</button>;\n * if (isLoading) return <p>Loading…</p>;\n * return <p>Blockhash: {data!.value.blockhash}</p>;\n * }\n *\n * // Function shape — wraps an arbitrary async call. The source can be an inline closure recreated\n * // each render; the hook reads the latest one when the query fires and keys the cache off `key`,\n * // so there's no need to memoize it.\n * function Profile({ userId }: { userId: string }) {\n * const { data, error, isLoading, refetch } = useRequestQuery(\n * ['users', userId],\n * (signal: AbortSignal) => fetch(`/api/users/${userId}`, { signal }).then(r => r.json()),\n * );\n * if (error) return <button onClick={() => refetch()}>Retry</button>;\n * if (isLoading) return <p>Loading…</p>;\n * return <p>{data!.name}</p>;\n * }\n * ```\n *\n * @see {@link UseRequestQueryOptions}\n */\nexport function useRequestQuery<T, TError = unknown, TData = T>(\n key: QueryKey,\n source: ReactiveActionSource<T> | ((signal: AbortSignal) => Promise<T>) | null,\n options?: UseRequestQueryOptions<T, TError, TData>,\n): UseQueryResult<TData, TError> {\n // Split our option off the TanStack config so we can hand the rest to `useQuery` cleanly.\n const { getAbortSignal, ...queryOptions } = options ?? {};\n\n // Ref-sync the source and the abort-signal factory so an inline closure passed each render\n // doesn't change the queryFn's identity. The queryFn reads the latest values from the refs when\n // it fires; TanStack uses the key (not the queryFn identity) for cache lookup.\n const sourceRef = useLatest(source);\n const getAbortSignalRef = useLatest(getAbortSignal);\n\n const queryFn = useCallback(\n async ({ signal }: QueryFunctionContext): Promise<T> => {\n const current = sourceRef.current;\n if (current == null) {\n // Defensive: a null source forces `enabled: false` below, so TanStack won't schedule\n // this queryFn. This branch should be unreachable.\n throw new Error('useRequestQuery: the queryFn ran with a null source');\n }\n const userSignal = getAbortSignalRef.current?.();\n // `signal` is TanStack's query-cancellation signal. Combine it with the caller's signal\n // (when present) so aborting either cancels the attempt.\n const combinedSignal = userSignal ? AbortSignal.any([signal, userSignal]) : signal;\n if (typeof current === 'function') {\n return await current(combinedSignal);\n }\n return await current.reactiveStore().withSignal(combinedSignal).dispatchAsync();\n // `sourceRef` and `getAbortSignalRef` are stable refs from `useLatest`, so listing them\n // leaves `queryFn` referentially stable across renders — TanStack keys off `key`, not\n // the queryFn identity, but a stable queryFn avoids needless churn.\n },\n [getAbortSignalRef, sourceRef],\n );\n\n return useQuery<T, TError, TData, QueryKey>({\n ...queryOptions,\n // A null source disables the query (TanStack's `enabled: false`). Combine with the caller's\n // own `enabled` so the query runs only when the source is present *and* the caller hasn't\n // disabled it.\n enabled: source != null && (queryOptions.enabled ?? true),\n queryFn,\n queryKey: key,\n });\n}\n","import { bridgeStoreToAsyncIterable, type ReactiveStreamSource } from '@solana/kit';\nimport {\n experimental_streamedQuery,\n type QueryFunction,\n type QueryFunctionContext,\n type QueryKey,\n useQuery,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\nimport { useLatest } from '../useLatest';\nimport type { UseRequestOptions } from '../useRequest';\n\n/**\n * Options accepted by {@link useSubscriptionQuery}: every option `@tanstack/react-query`'s `useQuery`\n * takes (minus `queryKey` and `queryFn`, which this hook owns) plus the Kit-specific\n * {@link UseRequestOptions}.\n *\n * @typeParam T - The notification type emitted by the source.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied.\n */\nexport type UseSubscriptionQueryOptions<T, TError = unknown, TData = T> = Omit<\n UseQueryOptions<T, TError, TData, QueryKey>,\n 'queryFn' | 'queryKey'\n> &\n UseRequestOptions;\n\n/**\n * TanStack Query-backed counterpart to core's `useSubscription`, for streams that have no one-shot\n * RPC fetch counterpart. Routes a long-lived stream through TanStack Query's cache via\n * `experimental_streamedQuery`, so components reading the same `key` share one underlying connection\n * and the stream participates in TanStack Query's cache and devtools.\n *\n * The source has the same two shapes as {@link useRequestQuery}, the pull-based analog of its\n * `(signal) => Promise<T>` arm: a {@link ReactiveStreamSource} (satisfied by an RPC subscription) or\n * a raw `(signal: AbortSignal) => AsyncIterable<T>` factory. `streamedQuery` is itself built on\n * `AsyncIterable`, so the factory's iterable is consumed directly; a `ReactiveStreamSource` is\n * adapted to one internally. The factory receives TanStack's query-cancellation signal (combined\n * with any `getAbortSignal` you supply) so a `fetch`- or socket-backed generator can bind\n * cancellation to it.\n *\n * `data` is the raw notification, exactly as the source emits it. For RPC subscriptions read\n * `data.value` and `data.context.slot` yourself.\n *\n * Because the stream never settles, the query stays in `fetchStatus: 'fetching'` for the\n * subscription's whole life — `isFetching` is permanently `true` and `isLoading` flips false\n * after the first notification. Read `data` / `error` / `status` and ignore `isFetching` for\n * subscriptions. `result.refetch()` reconnects: TanStack aborts the old signal (tearing the prior\n * stream's connection down) and opens a fresh stream. Fire and forget — for a never-ending stream\n * the returned promise never resolves, so don't `await refetch()` (a click handler that does will\n * hang forever).\n *\n * Defaults, all overridable: `retry: false` (the underlying reactive store owns retry/backoff),\n * `staleTime: Infinity` and `refetchOnWindowFocus: false` (a focus revalidation must not tear down\n * and re-open the socket — the subscription is what keeps data fresh). The internal `refetchMode` is\n * `'append'` paired with a replace-latest reducer: every notification is written to the cache live,\n * and the prior value stays visible across a reconnect (stale-while-revalidate).\n *\n * Pass `null` for `source` to disable — maps to TanStack's `enabled: false` and combines with any\n * `enabled` you pass (the query runs only when the source is non-null *and* your `enabled` is not\n * `false`).\n *\n * @typeParam T - The notification type emitted by the source.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to `T` when no\n * `select` is supplied; pass a `select: (data: T) => TData` option to project each notification into\n * a different shape and `result.data` narrows accordingly.\n *\n * @example\n * ```tsx\n * function SlotHeight() {\n * const client = useClient<ClientWithRpcSubscriptions<SlotNotificationsApi>>();\n * const { data, error } = useSubscriptionQuery(['slot'], client.rpcSubscriptions.slotNotifications());\n * if (error) return <p>Disconnected.</p>;\n * if (!data) return <p>Connecting…</p>;\n * return <p>Slot {String(data.slot)}</p>;\n * }\n *\n * // Function shape — wraps an arbitrary async iterable, threading the cancellation signal in.\n * function Ticker() {\n * const { data } = useSubscriptionQuery(['ticker'], (signal: AbortSignal) => streamPrices(signal));\n * return <p>{data ?? '…'}</p>;\n * }\n * ```\n *\n * @see {@link UseSubscriptionQueryOptions}\n * @see {@link useRequestQuery}\n */\nexport function useSubscriptionQuery<T, TError = unknown, TData = T>(\n key: QueryKey,\n source: ReactiveStreamSource<T> | ((signal: AbortSignal) => AsyncIterable<T>) | null,\n options?: UseSubscriptionQueryOptions<T, TError, TData>,\n): UseQueryResult<TData, TError> {\n // Split our option off the TanStack config so we can hand the rest to `useQuery` cleanly.\n const { getAbortSignal, ...queryOptions } = options ?? {};\n\n // Ref-sync the source and the abort-signal factory so an inline value passed each render doesn't\n // change the streamFn's identity. The streamFn reads the latest values from the refs when it\n // fires; TanStack uses the key (not the queryFn identity) for cache lookup.\n const sourceRef = useLatest(source);\n const getAbortSignalRef = useLatest(getAbortSignal);\n\n const queryFn = useCallback<QueryFunction<T, QueryKey>>(\n context =>\n // `streamedQuery`'s generics default to array accumulation (`TData = Array<TQueryFnData>`).\n // The explicit `<T, T>` plus a replace-latest reducer types the cache value as the latest\n // scalar notification rather than `T[]`. `initialValue` only seeds the (ignored) reducer\n // accumulator before the first chunk, so its value is irrelevant — only its type matters.\n experimental_streamedQuery<T, T>({\n initialValue: undefined as T,\n reducer: (_previous, chunk) => chunk,\n // `'append'` is the only mode that writes every chunk to the cache live while leaving\n // the prior value in place across a refetch. `'reset'` would flash to pending on each\n // reconnect; `'replace'` only flushes once at stream end — which for a never-ending\n // subscription never happens (an abort skips the final write), freezing the value.\n refetchMode: 'append',\n streamFn: ({ signal }: QueryFunctionContext) => {\n const current = sourceRef.current;\n if (current == null) {\n // Defensive: a null source forces `enabled: false` below, so TanStack won't\n // schedule this queryFn. This branch should be unreachable.\n throw new Error('useSubscriptionQuery: the streamFn ran with a null source');\n }\n const userSignal = getAbortSignalRef.current?.();\n // `signal` is TanStack's query-cancellation signal. Combine it with the caller's\n // signal (when present) so aborting either tears the stream down.\n const combinedSignal = userSignal ? AbortSignal.any([signal, userSignal]) : signal;\n if (typeof current === 'function') {\n return current(combinedSignal);\n }\n const store = current.reactiveStore();\n // reset not needed, the connection tears down and the store gets GCed after abort\n store.withSignal(combinedSignal).connect();\n return bridgeStoreToAsyncIterable(store, combinedSignal);\n },\n })(context),\n [getAbortSignalRef, sourceRef],\n );\n\n return useQuery<T, TError, TData, QueryKey>({\n // Sensible defaults for a long-lived stream; all overridable by `queryOptions` below.\n refetchOnWindowFocus: false,\n retry: false,\n staleTime: Infinity,\n ...queryOptions,\n // A null source disables the query (TanStack's `enabled: false`). Combine with the caller's\n // own `enabled` so the query runs only when the source is present *and* not disabled.\n enabled: source != null && (queryOptions.enabled ?? true),\n queryFn,\n queryKey: key,\n });\n}\n","import {\n bridgeStoreToAsyncIterable,\n createReactiveStoreWithInitialValueAndSlotTracking,\n type SolanaRpcResponse,\n} from '@solana/kit';\nimport {\n experimental_streamedQuery,\n type QueryFunction,\n type QueryFunctionContext,\n type QueryKey,\n useQuery,\n useQueryClient,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\nimport { useLatest } from '../useLatest';\nimport type { UseRequestOptions } from '../useRequest';\nimport type { TrackedDataSpec } from '../useTrackedData';\n\n/**\n * Options accepted by {@link useTrackedDataQuery}: every option `@tanstack/react-query`'s `useQuery`\n * takes (minus `queryKey` and `queryFn`, which this hook owns) plus the Kit-specific\n * {@link UseRequestOptions}.\n *\n * @typeParam TItem - The unified item type produced by the spec's two mappers, surfaced as\n * `data.value`.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to the\n * `SolanaRpcResponse<TItem>` envelope when no `select` is supplied.\n */\nexport type UseTrackedDataQueryOptions<TItem, TError = unknown, TData = SolanaRpcResponse<TItem>> = Omit<\n UseQueryOptions<SolanaRpcResponse<TItem>, TError, TData, QueryKey>,\n 'queryFn' | 'queryKey'\n> &\n UseRequestOptions;\n\n/**\n * TanStack Query-backed counterpart to core's `useTrackedData`. Pairs a one-shot RPC fetch with an\n * ongoing subscription (slot-deduped by the underlying Kit primitive) and routes the unified stream\n * through TanStack Query's cache via `experimental_streamedQuery`, so components reading the same\n * `key` share one underlying connection and the stream participates in TanStack Query's cache and\n * devtools.\n *\n * `data` is the `SolanaRpcResponse<TItem>` envelope emitted by the underlying kit primitive — the\n * primitive's type guarantees the envelope shape, so callers can read `data.value` (the unified item\n * produced by the spec's mappers) and `data.context.slot` (the slot the store dedup'd on) directly.\n *\n * Pass a {@link TrackedDataSpec} keyed on whatever inputs it depends on; the hook reads the latest\n * one from a ref, so an inline spec recreated each render is fine (TanStack keys the cache off `key`,\n * not the spec identity — bump the `key` to swap specs). Pass `null` for `spec` to disable — maps to\n * TanStack's `enabled: false` and combines with any `enabled` you pass (the query runs only when the\n * spec is non-null *and* your `enabled` is not `false`).\n *\n * Because the subscription never settles, the query stays in `fetchStatus: 'fetching'` for its whole\n * life — `isFetching` is permanently `true` and `isLoading` flips false after the first value. Read\n * `data` / `error` / `status` and ignore `isFetching`. `result.refetch()` reconnects: TanStack aborts\n * the old signal (tearing the prior stream's connection down) and re-runs both the initial RPC fetch\n * and the subscription. Fire and forget — for a never-ending stream the returned promise never\n * resolves, so don't `await refetch()`.\n *\n * Defaults, all overridable: `retry: false` (the underlying reactive store owns retry/backoff),\n * `staleTime: Infinity` and `refetchOnWindowFocus: false` (a focus revalidation must not tear down\n * and re-open the socket — the subscription is what keeps data fresh). The internal `refetchMode` is\n * `'append'` paired with a replace-latest reducer: every value is written to the cache live, and the\n * prior value stays visible across a reconnect (stale-while-revalidate).\n *\n * Slot dedupe spans the TanStack cache, not just one store. The underlying primitive tracks a slot\n * high-water mark per store, but that mark dies when the store is disposed while the cache entry\n * survives. `refetch()` mints a fresh store (high-water reset to -1) while `refetchMode: 'append'`\n * keeps the prior envelope cached, so this hook bridges that gap: the reconnect's fresh store cannot\n * regress the cached envelope to an older slot — e.g. a lagging RPC node resolving the new initial\n * fetch behind the cached value is refused, and the warmer cached value stands until something newer\n * arrives.\n *\n * @typeParam TInitialValue - The value inside the initial RPC `SolanaRpcResponse` envelope.\n * @typeParam TStreamValue - The value inside subscription `SolanaRpcResponse` notifications.\n * @typeParam TItem - The unified item type produced by the two mappers, surfaced as `data.value`.\n * @typeParam TError - The error type TanStack Query will surface on failure.\n * @typeParam TData - The shape of `data` after any `select` transform. Defaults to the\n * `SolanaRpcResponse<TItem>` envelope when no `select` is supplied; pass a\n * `select: (data: SolanaRpcResponse<TItem>) => TData` option to project each value into a different\n * shape and `result.data` narrows accordingly.\n *\n * @example\n * ```tsx\n * function AccountBalance({ address }: { address: Address }) {\n * const client = useClient<ClientWithRpc<GetBalanceApi> & ClientWithRpcSubscriptions<AccountNotificationsApi>>();\n * const spec = useMemo(() => ({\n * initialValueSource: client.rpc.getBalance(address),\n * initialValueMapper: (lamports: bigint) => lamports,\n * streamSource: client.rpcSubscriptions.accountNotifications(address),\n * streamValueMapper: ({ lamports }: { lamports: bigint }) => lamports,\n * }), [client, address]);\n * const { data, error } = useTrackedDataQuery(['balance', address], spec);\n * if (error) return <p>Failed to load.</p>;\n * return <p>{data ? `${data.value} lamports at slot ${data.context.slot}` : 'Loading…'}</p>;\n * }\n * ```\n *\n * @see {@link UseTrackedDataQueryOptions}\n * @see {@link useSubscriptionQuery}\n */\nexport function useTrackedDataQuery<\n TInitialValue,\n TStreamValue,\n TItem,\n TError = unknown,\n TData = SolanaRpcResponse<TItem>,\n>(\n key: QueryKey,\n spec: TrackedDataSpec<TInitialValue, TStreamValue, TItem> | null,\n options?: UseTrackedDataQueryOptions<TItem, TError, TData>,\n): UseQueryResult<TData, TError> {\n // Split our option off the TanStack config so we can hand the rest to `useQuery` cleanly.\n const { getAbortSignal, ...queryOptions } = options ?? {};\n\n // Ref-sync the spec and the abort-signal factory so an inline value passed each render doesn't\n // change the streamFn's identity. The streamFn reads the latest values from the refs when it\n // fires; TanStack uses the key (not the queryFn identity) for cache lookup.\n const specRef = useLatest(spec);\n const getAbortSignalRef = useLatest(getAbortSignal);\n\n // The cache outlives the per-attempt store, but the store's slot high-water mark does not — a\n // fresh store (remount, refetch) starts its window at -1. The streamFn reads the currently\n // cached envelope through this client to refuse any value older than what the cache already\n // holds. `useQueryClient` returns a stable reference, so listing it in the deps below is churn-free.\n const queryClient = useQueryClient();\n\n const queryFn = useCallback<QueryFunction<SolanaRpcResponse<TItem>, QueryKey>>(\n context =>\n // `streamedQuery`'s generics default to array accumulation (`TData = Array<TQueryFnData>`).\n // The explicit `<Envelope, Envelope>` plus a replace-latest reducer types the cache value\n // as the latest scalar envelope rather than an array. `initialValue` only seeds the\n // (ignored) reducer accumulator before the first chunk, so its value is irrelevant — only\n // its type matters.\n experimental_streamedQuery<SolanaRpcResponse<TItem>, SolanaRpcResponse<TItem>>({\n initialValue: undefined as unknown as SolanaRpcResponse<TItem>,\n reducer: (_previous, chunk) => chunk,\n // `'append'` is the only mode that writes every chunk to the cache live while leaving\n // the prior value in place across a refetch. `'reset'` would flash to pending on each\n // reconnect; `'replace'` only flushes once at stream end — which for a never-ending\n // subscription never happens (an abort skips the final write), freezing the value.\n refetchMode: 'append',\n streamFn: ({ queryKey, signal }: QueryFunctionContext) => {\n const current = specRef.current;\n if (current == null) {\n // Defensive: a null spec forces `enabled: false` below, so TanStack won't\n // schedule this queryFn. This branch should be unreachable.\n throw new Error('useTrackedDataQuery: the streamFn ran with a null spec');\n }\n const userSignal = getAbortSignalRef.current?.();\n // `signal` is TanStack's query-cancellation signal. Combine it with the caller's\n // signal (when present) so aborting either tears the stream down.\n const combinedSignal = userSignal ? AbortSignal.any([signal, userSignal]) : signal;\n const store = createReactiveStoreWithInitialValueAndSlotTracking(current);\n // reset not needed, the connection tears down and the store gets GCed after abort\n store.withSignal(combinedSignal).connect();\n // Refuse any envelope older than the slot the cache already holds. A fresh store\n // (e.g. after a remount) tracks slots from scratch, so without this it could\n // overwrite the cached value with an older one from a lagging RPC node.\n return bridgeStoreToAsyncIterable(store, combinedSignal, value => {\n const cachedSlot =\n queryClient.getQueryData<SolanaRpcResponse<TItem>>(queryKey)?.context.slot ?? -1n;\n return value.context.slot > cachedSlot;\n });\n },\n })(context),\n [getAbortSignalRef, queryClient, specRef],\n );\n\n return useQuery<SolanaRpcResponse<TItem>, TError, TData, QueryKey>({\n // Sensible defaults for a long-lived stream; all overridable by `queryOptions` below.\n refetchOnWindowFocus: false,\n retry: false,\n staleTime: Infinity,\n ...queryOptions,\n // A null spec disables the query (TanStack's `enabled: false`). Combine with the caller's own\n // `enabled` so the query runs only when the spec is present *and* not disabled.\n enabled: spec != null && (queryOptions.enabled ?? true),\n queryFn,\n queryKey: key,\n });\n}\n"]}
@@ -5,9 +5,16 @@
5
5
  */
6
6
  export * from './ClientProvider';
7
7
  export * from './useAction';
8
+ export * from './useAirdrop';
8
9
  export * from './useClient';
9
10
  export * from './useClientCapability';
11
+ export * from './useIdentity';
12
+ export * from './usePayer';
13
+ export * from './usePlanTransaction';
14
+ export * from './usePlanTransactions';
10
15
  export * from './useRequest';
16
+ export * from './useSendTransaction';
17
+ export * from './useSendTransactions';
11
18
  export * from './useSignAndSendTransaction';
12
19
  export * from './useSubscription';
13
20
  export * from './useSignIn';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { ReactiveStreamSource } from '@solana/kit';
1
+ import { type ReactiveStreamSource } from '@solana/kit';
2
2
  import { type QueryKey, type UseQueryOptions, type UseQueryResult } from '@tanstack/react-query';
3
3
  import type { UseRequestOptions } from '../useRequest';
4
4
  /**
@@ -32,10 +32,10 @@ export type UseSubscriptionQueryOptions<T, TError = unknown, TData = T> = Omit<U
32
32
  * Because the stream never settles, the query stays in `fetchStatus: 'fetching'` for the
33
33
  * subscription's whole life — `isFetching` is permanently `true` and `isLoading` flips false
34
34
  * after the first notification. Read `data` / `error` / `status` and ignore `isFetching` for
35
- * subscriptions. `result.refetch()` reconnects: TanStack aborts the old signal (ending the prior
36
- * iterable, which resets its store) and opens a fresh stream. Fire and forget — for a never-ending
37
- * stream the returned promise never resolves, so don't `await refetch()` (a click handler that does
38
- * will hang forever).
35
+ * subscriptions. `result.refetch()` reconnects: TanStack aborts the old signal (tearing the prior
36
+ * stream's connection down) and opens a fresh stream. Fire and forget — for a never-ending stream
37
+ * the returned promise never resolves, so don't `await refetch()` (a click handler that does will
38
+ * hang forever).
39
39
  *
40
40
  * Defaults, all overridable: `retry: false` (the underlying reactive store owns retry/backoff),
41
41
  * `staleTime: Infinity` and `refetchOnWindowFocus: false` (a focus revalidation must not tear down
@@ -1 +1 @@
1
- {"version":3,"file":"useSubscriptionQuery.d.ts","sourceRoot":"","sources":["../../../src/query/useSubscriptionQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAIH,KAAK,QAAQ,EAEb,KAAK,eAAe,EACpB,KAAK,cAAc,EACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGvD;;;;;;;;;GASG;AACH,MAAM,MAAM,2BAA2B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC,IAAI,IAAI,CAC1E,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,EAC3C,SAAS,GAAG,UAAU,CACzB,GACG,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC,EAC/D,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EACpF,OAAO,CAAC,EAAE,2BAA2B,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,GACxD,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAwD/B"}
1
+ {"version":3,"file":"useSubscriptionQuery.d.ts","sourceRoot":"","sources":["../../../src/query/useSubscriptionQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAIH,KAAK,QAAQ,EAEb,KAAK,eAAe,EACpB,KAAK,cAAc,EACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;;;;;;GASG;AACH,MAAM,MAAM,2BAA2B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC,IAAI,IAAI,CAC1E,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,EAC3C,SAAS,GAAG,UAAU,CACzB,GACG,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC,EAC/D,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EACpF,OAAO,CAAC,EAAE,2BAA2B,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,GACxD,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CA2D/B"}
@@ -34,8 +34,8 @@ export type UseTrackedDataQueryOptions<TItem, TError = unknown, TData = SolanaRp
34
34
  * Because the subscription never settles, the query stays in `fetchStatus: 'fetching'` for its whole
35
35
  * life — `isFetching` is permanently `true` and `isLoading` flips false after the first value. Read
36
36
  * `data` / `error` / `status` and ignore `isFetching`. `result.refetch()` reconnects: TanStack aborts
37
- * the old signal (ending the prior iterable, which resets its store) and re-runs both the initial RPC
38
- * fetch and the subscription. Fire and forget — for a never-ending stream the returned promise never
37
+ * the old signal (tearing the prior stream's connection down) and re-runs both the initial RPC fetch
38
+ * and the subscription. Fire and forget — for a never-ending stream the returned promise never
39
39
  * resolves, so don't `await refetch()`.
40
40
  *
41
41
  * Defaults, all overridable: `retry: false` (the underlying reactive store owns retry/backoff),
@@ -1 +1 @@
1
- {"version":3,"file":"useTrackedDataQuery.d.ts","sourceRoot":"","sources":["../../../src/query/useTrackedDataQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsD,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAIH,KAAK,QAAQ,EAGb,KAAK,eAAe,EACpB,KAAK,cAAc,EACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,IAAI,CACpG,eAAe,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,EAClE,SAAS,GAAG,UAAU,CACzB,GACG,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,wBAAgB,mBAAmB,CAC/B,aAAa,EACb,YAAY,EACZ,KAAK,EACL,MAAM,GAAG,OAAO,EAChB,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,EAEhC,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,eAAe,CAAC,aAAa,EAAE,YAAY,EAAE,KAAK,CAAC,GAAG,IAAI,EAChE,OAAO,CAAC,EAAE,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAC3D,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAoE/B"}
1
+ {"version":3,"file":"useTrackedDataQuery.d.ts","sourceRoot":"","sources":["../../../src/query/useTrackedDataQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,iBAAiB,EACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAIH,KAAK,QAAQ,EAGb,KAAK,eAAe,EACpB,KAAK,cAAc,EACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,IAAI,CACpG,eAAe,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,EAClE,SAAS,GAAG,UAAU,CACzB,GACG,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,wBAAgB,mBAAmB,CAC/B,aAAa,EACb,YAAY,EACZ,KAAK,EACL,MAAM,GAAG,OAAO,EAChB,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,EAEhC,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,eAAe,CAAC,aAAa,EAAE,YAAY,EAAE,KAAK,CAAC,GAAG,IAAI,EAChE,OAAO,CAAC,EAAE,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAC3D,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAsE/B"}
@@ -0,0 +1,40 @@
1
+ import type { Address, ClientWithAirdrop, Lamports, Signature } from '@solana/kit';
2
+ import { type ActionResult } from './useAction';
3
+ /**
4
+ * Requests an airdrop of SOL to an address, as a reactive action.
5
+ *
6
+ * Wraps `client.airdrop` with {@link useAction}: each `dispatch(address, amount)` runs the airdrop
7
+ * with a fresh `AbortSignal` and tracks its lifecycle through React state. Calling `dispatch` again
8
+ * while a previous airdrop is in flight aborts the first. This is a great fit for a devnet or
9
+ * localnet "fund this account" button, where the `isRunning` / `data` / `error` tracking drives the
10
+ * UI directly.
11
+ *
12
+ * The airdrop capability is typically available on test networks (devnet, testnet) and local
13
+ * validators. Some implementations (e.g. LiteSVM) update balances directly without sending a
14
+ * transaction, in which case the resolved `data` is `undefined` rather than a {@link Signature}.
15
+ *
16
+ * @param client - A client with an airdrop plugin installed (`ClientWithAirdrop`).
17
+ * @returns An {@link ActionResult} whose `dispatch`/`dispatchAsync` take the recipient `address` and
18
+ * the `amount` of lamports, and resolve with the transaction {@link Signature}, or `undefined`
19
+ * when the airdrop was performed without a transaction.
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * import { useAirdrop } from '@solana/react';
24
+ * import { lamports } from '@solana/kit';
25
+ *
26
+ * function AirdropButton({ client, address }) {
27
+ * const { dispatch, isRunning } = useAirdrop(client);
28
+ * return (
29
+ * <button disabled={isRunning} onClick={() => dispatch(address, lamports(1_000_000_000n))}>
30
+ * {isRunning ? 'Airdropping…' : 'Airdrop 1 SOL'}
31
+ * </button>
32
+ * );
33
+ * }
34
+ * ```
35
+ *
36
+ * @see {@link ActionResult}
37
+ * @see {@link useAction}
38
+ */
39
+ export declare function useAirdrop(client: ClientWithAirdrop): ActionResult<[address: Address, amount: Lamports], Signature | undefined>;
40
+ //# sourceMappingURL=useAirdrop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAirdrop.d.ts","sourceRoot":"","sources":["../../src/useAirdrop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnF,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,UAAU,CACtB,MAAM,EAAE,iBAAiB,GAC1B,YAAY,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,CAE3E"}
@@ -4,12 +4,13 @@ import { type Client } from '@solana/kit';
4
4
  * {@link SolanaError} with code {@link SOLANA_ERROR__REACT__MISSING_PROVIDER} if no provider is
5
5
  * mounted in the ancestor tree.
6
6
  *
7
- * Defaults to the base {@link Client} shape. Callers who know a specific plugin is installed may
8
- * widen the type via the generic — this is a pure cast with no runtime capability check, so reach
9
- * for {@link useClientCapability} when a missing plugin should fail loudly at mount instead of
10
- * surfacing later as `undefined`.
7
+ * Pass the shape of your client through the generic (typically the `AppClient` type you export
8
+ * alongside the client) so every installed capability is typed at the call site. This is a pure
9
+ * cast with no runtime capability check, so reach for {@link useClientCapability} when a missing
10
+ * plugin should fail loudly at mount instead of surfacing later as `undefined`.
11
11
  *
12
- * @typeParam TClient - The shape the client is expected to satisfy. Pure type assertion.
12
+ * @typeParam TClient - The shape the client is expected to satisfy. Pure type assertion, so this
13
+ * must always be supplied — the hook can't infer it from its (absent) arguments.
13
14
  *
14
15
  * @example
15
16
  * ```tsx
@@ -25,5 +26,5 @@ import { type Client } from '@solana/kit';
25
26
  * @see {@link ClientProvider}
26
27
  * @see {@link useClientCapability}
27
28
  */
28
- export declare function useClient<TClient extends object = object>(): Client<TClient>;
29
+ export declare function useClient<TClient extends object>(): Client<TClient>;
29
30
  //# sourceMappingURL=useClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useClient.d.ts","sourceRoot":"","sources":["../../src/useClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAsD,MAAM,aAAa,CAAC;AAK9F;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,CAM5E"}
1
+ {"version":3,"file":"useClient.d.ts","sourceRoot":"","sources":["../../src/useClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAsD,MAAM,aAAa,CAAC;AAK9F;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CAAC,OAAO,SAAS,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,CAMnE"}
@@ -0,0 +1,28 @@
1
+ import type { ClientWithIdentity, ClientWithSubscribeToIdentity, TransactionSigner } from '@solana/kit';
2
+ /**
3
+ * Reads `client.identity` and re-renders whenever it changes, returning `undefined` while no
4
+ * identity is available.
5
+ *
6
+ * The identity is the {@link TransactionSigner} representing the wallet whose on-chain assets the
7
+ * application is acting upon.
8
+ *
9
+ * When the client advertises {@link ClientWithSubscribeToIdentity},
10
+ * this hook subscribes via `client.subscribeToIdentity` so the returned value always reflects the
11
+ * latest identity. For a client whose identity is fixed for its lifetime, the hook falls back to a
12
+ * no-op subscription and simply reads the value once.
13
+ *
14
+ * @param client - A client with an identity plugin installed. If it also advertises
15
+ * `subscribeToIdentity`, the hook tracks changes reactively.
16
+ * @returns The current `client.identity` signer, or `undefined` if no identity is currently
17
+ * available.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * const identity = useIdentity(client);
22
+ * return <span>{identity ? `Signed in as ${identity.address}` : 'Signed out'}</span>;
23
+ * ```
24
+ *
25
+ * @see {@link usePayer}
26
+ */
27
+ export declare function useIdentity(client: ClientWithIdentity & Partial<ClientWithSubscribeToIdentity>): TransactionSigner | undefined;
28
+ //# sourceMappingURL=useIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIdentity.d.ts","sourceRoot":"","sources":["../../src/useIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKxG;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,WAAW,CACvB,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,6BAA6B,CAAC,GACpE,iBAAiB,GAAG,SAAS,CAc/B"}
@@ -0,0 +1,27 @@
1
+ import type { ClientWithPayer, ClientWithSubscribeToPayer, TransactionSigner } from '@solana/kit';
2
+ /**
3
+ * Reads `client.payer` and re-renders whenever it changes, returning `undefined` while no payer is
4
+ * available.
5
+ *
6
+ * The payer is the {@link TransactionSigner} a client uses to sign and pay for transactions by
7
+ * default.
8
+ *
9
+ * When the client advertises {@link ClientWithSubscribeToPayer}, this hook subscribes via
10
+ * `client.subscribeToPayer` so the returned value always reflects the latest payer. For a client
11
+ * whose payer is fixed for its lifetime, the hook falls back to a no-op subscription and simply
12
+ * reads the value once.
13
+ *
14
+ * @param client - A client with a payer plugin installed. If it also advertises
15
+ * `subscribeToPayer`, the hook tracks changes reactively.
16
+ * @returns The current `client.payer` signer, or `undefined` if no payer is currently available.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const payer = usePayer(client);
21
+ * return <span>{payer ? `Paying with ${payer.address}` : 'No payer'}</span>;
22
+ * ```
23
+ *
24
+ * @see {@link useIdentity}
25
+ */
26
+ export declare function usePayer(client: ClientWithPayer & Partial<ClientWithSubscribeToPayer>): TransactionSigner | undefined;
27
+ //# sourceMappingURL=usePayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePayer.d.ts","sourceRoot":"","sources":["../../src/usePayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKlG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,0BAA0B,CAAC,GAAG,iBAAiB,GAAG,SAAS,CAcrH"}
@@ -0,0 +1,25 @@
1
+ import type { ClientWithTransactionPlanning, InstructionPlanInput, SingleTransactionPlan } from '@solana/kit';
2
+ import { type ActionResult } from './useAction';
3
+ /**
4
+ * Plans a single transaction from an instruction input, as a reactive action.
5
+ *
6
+ * Wraps `client.planTransaction` with {@link useAction}: each `dispatch(input)` runs the plan with a
7
+ * fresh `AbortSignal` and tracks its lifecycle through React state. Calling `dispatch` again while a
8
+ * previous plan is in flight aborts the first. Use this when you expect all instructions to fit in a
9
+ * single transaction; reach for {@link usePlanTransactions} when they might need splitting.
10
+ *
11
+ * @param client - A client with a transaction-planning plugin installed.
12
+ * @returns An {@link ActionResult} whose `dispatch`/`dispatchAsync` take the
13
+ * {@link InstructionPlanInput} and resolve with the planned transaction message.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const { dispatch, data, isRunning } = usePlanTransaction(client);
18
+ * <button disabled={isRunning} onClick={() => dispatch(instructions)}>Plan</button>
19
+ * ```
20
+ *
21
+ * @see {@link usePlanTransactions}
22
+ * @see {@link useSendTransaction}
23
+ */
24
+ export declare function usePlanTransaction(client: ClientWithTransactionPlanning): ActionResult<[input: InstructionPlanInput], SingleTransactionPlan['message']>;
25
+ //# sourceMappingURL=usePlanTransaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePlanTransaction.d.ts","sourceRoot":"","sources":["../../src/usePlanTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE9G,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,6BAA6B,GACtC,YAAY,CAAC,CAAC,KAAK,EAAE,oBAAoB,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAE/E"}
@@ -0,0 +1,26 @@
1
+ import type { ClientWithTransactionPlanning, InstructionPlanInput, TransactionPlan } from '@solana/kit';
2
+ import { type ActionResult } from './useAction';
3
+ /**
4
+ * Plans one or more transactions from an instruction input, as a reactive action.
5
+ *
6
+ * Wraps `client.planTransactions` with {@link useAction}: each `dispatch(input)` runs the plan with a
7
+ * fresh `AbortSignal` and tracks its lifecycle through React state. Calling `dispatch` again while a
8
+ * previous plan is in flight aborts the first. Use this when the instructions might be split across
9
+ * multiple transactions due to size limits; reach for {@link usePlanTransaction} for the single-
10
+ * transaction case.
11
+ *
12
+ * @param client - A client with a transaction-planning plugin installed.
13
+ * @returns An {@link ActionResult} whose `dispatch`/`dispatchAsync` take the
14
+ * {@link InstructionPlanInput} and resolve with the full {@link TransactionPlan}.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * const { dispatch, data, isRunning } = usePlanTransactions(client);
19
+ * <button disabled={isRunning} onClick={() => dispatch(instructions)}>Plan</button>
20
+ * ```
21
+ *
22
+ * @see {@link usePlanTransaction}
23
+ * @see {@link useSendTransactions}
24
+ */
25
+ export declare function usePlanTransactions(client: ClientWithTransactionPlanning): ActionResult<[input: InstructionPlanInput], TransactionPlan>;
26
+ //# sourceMappingURL=usePlanTransactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePlanTransactions.d.ts","sourceRoot":"","sources":["../../src/usePlanTransactions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAExG,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,6BAA6B,GACtC,YAAY,CAAC,CAAC,KAAK,EAAE,oBAAoB,CAAC,EAAE,eAAe,CAAC,CAE9D"}
@@ -0,0 +1,29 @@
1
+ import type { ClientWithTransactionSending, SuccessfulSingleTransactionPlanResult } from '@solana/kit';
2
+ import { type ActionResult } from './useAction';
3
+ type SendTransactionInput = Parameters<ClientWithTransactionSending['sendTransaction']>[0];
4
+ /**
5
+ * Sends a single transaction to the network, as a reactive action.
6
+ *
7
+ * Wraps `client.sendTransaction` with {@link useAction}, which handles signing, submission, and
8
+ * confirmation. Each `dispatch(input)` runs with a fresh `AbortSignal` and tracks its lifecycle
9
+ * through React state; calling `dispatch` again while a previous send is in flight aborts the first.
10
+ * Accepts flexible input: instructions, an instruction plan, a single transaction message, or a
11
+ * single transaction plan. Use {@link useSendTransactions} when the work may span multiple
12
+ * transactions.
13
+ *
14
+ * @param client - A client with a transaction-sending plugin installed.
15
+ * @returns An {@link ActionResult} whose `dispatch`/`dispatchAsync` take the input and resolve with
16
+ * the {@link SuccessfulSingleTransactionPlanResult}.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const { dispatch, data, isRunning } = useSendTransaction(client);
21
+ * <button disabled={isRunning} onClick={() => dispatch(instructions)}>Send</button>
22
+ * ```
23
+ *
24
+ * @see {@link useSendTransactions}
25
+ * @see {@link usePlanTransaction}
26
+ */
27
+ export declare function useSendTransaction(client: ClientWithTransactionSending): ActionResult<[input: SendTransactionInput], SuccessfulSingleTransactionPlanResult>;
28
+ export {};
29
+ //# sourceMappingURL=useSendTransaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSendTransaction.d.ts","sourceRoot":"","sources":["../../src/useSendTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,qCAAqC,EAAE,MAAM,aAAa,CAAC;AAEvG,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAE3D,KAAK,oBAAoB,GAAG,UAAU,CAAC,4BAA4B,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3F;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,4BAA4B,GACrC,YAAY,CAAC,CAAC,KAAK,EAAE,oBAAoB,CAAC,EAAE,qCAAqC,CAAC,CAEpF"}
@@ -0,0 +1,28 @@
1
+ import type { ClientWithTransactionSending, TransactionPlanResult } from '@solana/kit';
2
+ import { type ActionResult } from './useAction';
3
+ type SendTransactionsInput = Parameters<ClientWithTransactionSending['sendTransactions']>[0];
4
+ /**
5
+ * Sends one or more transactions to the network, as a reactive action.
6
+ *
7
+ * Wraps `client.sendTransactions` with {@link useAction}, which handles signing, submission, and
8
+ * confirmation. Each `dispatch(input)` runs with a fresh `AbortSignal` and tracks its lifecycle
9
+ * through React state; calling `dispatch` again while a previous send is in flight aborts the first.
10
+ * Accepts flexible input: instructions, an instruction plan, or a transaction plan. Use
11
+ * {@link useSendTransaction} for the single-transaction case.
12
+ *
13
+ * @param client - A client with a transaction-sending plugin installed.
14
+ * @returns An {@link ActionResult} whose `dispatch`/`dispatchAsync` take the input and resolve with
15
+ * the {@link TransactionPlanResult} for all transactions.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * const { dispatch, data, isRunning } = useSendTransactions(client);
20
+ * <button disabled={isRunning} onClick={() => dispatch(instructions)}>Send</button>
21
+ * ```
22
+ *
23
+ * @see {@link useSendTransaction}
24
+ * @see {@link usePlanTransactions}
25
+ */
26
+ export declare function useSendTransactions(client: ClientWithTransactionSending): ActionResult<[input: SendTransactionsInput], TransactionPlanResult>;
27
+ export {};
28
+ //# sourceMappingURL=useSendTransactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSendTransactions.d.ts","sourceRoot":"","sources":["../../src/useSendTransactions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEvF,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAE3D,KAAK,qBAAqB,GAAG,UAAU,CAAC,4BAA4B,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,4BAA4B,GACrC,YAAY,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC,EAAE,qBAAqB,CAAC,CAErE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/react",
3
- "version": "7.0.0",
3
+ "version": "7.1.0-canary-20260812160611",
4
4
  "description": "React hooks for building Solana apps",
5
5
  "homepage": "https://www.solanakit.com/api#solanareact",
6
6
  "exports": {
@@ -106,19 +106,19 @@
106
106
  "@wallet-standard/base": "^1.1.0",
107
107
  "@wallet-standard/errors": "^0.1.2",
108
108
  "@wallet-standard/react": "^1.0.1",
109
- "@wallet-standard/ui": "^1.0.1",
110
- "@wallet-standard/ui-registry": "^1.0.1",
111
- "@solana/promises": "7.0.0",
112
- "@solana/signers": "7.0.0",
113
- "@solana/transaction-messages": "7.0.0",
114
- "@solana/transactions": "7.0.0",
115
- "@solana/subscribable": "7.0.0"
109
+ "@wallet-standard/ui": "^1.0.3",
110
+ "@wallet-standard/ui-registry": "^1.1.1",
111
+ "@solana/promises": "7.1.0-canary-20260812160611",
112
+ "@solana/signers": "7.1.0-canary-20260812160611",
113
+ "@solana/transaction-messages": "7.1.0-canary-20260812160611",
114
+ "@solana/transactions": "7.1.0-canary-20260812160611",
115
+ "@solana/subscribable": "7.1.0-canary-20260812160611"
116
116
  },
117
117
  "peerDependencies": {
118
118
  "@tanstack/react-query": "^5.0.0",
119
119
  "react": ">=18",
120
- "swr": "^2.0.0",
121
- "@solana/kit": "7.0.0"
120
+ "swr": "^2.4.2",
121
+ "@solana/kit": "^7.1.0-canary-20260812160611"
122
122
  },
123
123
  "peerDependenciesMeta": {
124
124
  "@tanstack/react-query": {
package/src/index.ts CHANGED
@@ -5,9 +5,16 @@
5
5
  */
6
6
  export * from './ClientProvider';
7
7
  export * from './useAction';
8
+ export * from './useAirdrop';
8
9
  export * from './useClient';
9
10
  export * from './useClientCapability';
11
+ export * from './useIdentity';
12
+ export * from './usePayer';
13
+ export * from './usePlanTransaction';
14
+ export * from './usePlanTransactions';
10
15
  export * from './useRequest';
16
+ export * from './useSendTransaction';
17
+ export * from './useSendTransactions';
11
18
  export * from './useSignAndSendTransaction';
12
19
  export * from './useSubscription';
13
20
  export * from './useSignIn';
@@ -34,8 +34,8 @@ function createWrapper() {
34
34
  type DeepPartial<T> = T extends (...args: infer A) => infer R
35
35
  ? (...args: A) => DeepPartial<R>
36
36
  : T extends object
37
- ? { [K in keyof T]?: DeepPartial<T[K]> }
38
- : T;
37
+ ? { [K in keyof T]?: DeepPartial<T[K]> }
38
+ : T;
39
39
 
40
40
  // Wraps a partial `ReactiveActionStore` stub into a `ReactiveActionSource`, isolating the
41
41
  // type-narrowing cast to one place so spy-on-store tests stay legible.