@solana/react-hooks 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { createClient, toAddress, toAddressString, stableStringify, createSolTransferController, createSplTransferController, getWalletStandardConnectors, watchWalletStandardConnectors, createTransactionPoolController, createInitialAsyncState, createAsyncState, normalizeSignature, SIGNATURE_STATUS_TIMEOUT_MS, deriveConfirmationStatus, confirmationMeetsCommitment, deserializeSolanaState, subscribeSolanaState, serializeSolanaState } from '@solana/client';
1
+ import { createClient, toAddress, toAddressString, stableStringify, createSolTransferController, createSplTransferController, createTransactionPoolController, createInitialAsyncState, createAsyncState, normalizeSignature, SIGNATURE_STATUS_TIMEOUT_MS, deriveConfirmationStatus, confirmationMeetsCommitment, deserializeSolanaState, subscribeSolanaState, serializeSolanaState } from '@solana/client';
2
2
  import { createContext, useMemo, useEffect, useContext, useCallback, useRef, useSyncExternalStore, useState } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import useSWR, { SWRConfig } from 'swr';
@@ -56,11 +56,11 @@ var QUERY_NAMESPACE = "@solana/react-hooks";
56
56
  function useSolanaRpcQuery(scope, args, fetcher, options = {}) {
57
57
  const client = useSolanaClient();
58
58
  const cluster = useClientStore((state) => state.cluster);
59
- const { disabled = false, ...restOptions } = options;
59
+ const { disabled = false, swr } = options;
60
60
  const providerSuspensePreference = useQuerySuspensePreference();
61
61
  const suspenseEnabled = !disabled && Boolean(providerSuspensePreference);
62
62
  const swrOptions = {
63
- ...restOptions,
63
+ ...swr ?? {},
64
64
  suspense: suspenseEnabled
65
65
  };
66
66
  const key = useMemo(() => {
@@ -69,59 +69,105 @@ function useSolanaRpcQuery(scope, args, fetcher, options = {}) {
69
69
  }
70
70
  return [QUERY_NAMESPACE, scope, cluster.endpoint, cluster.commitment, ...args];
71
71
  }, [cluster.commitment, cluster.endpoint, args, scope, disabled]);
72
- const swr = useSWR(key, () => fetcher(client), swrOptions);
72
+ const swrResponse = useSWR(key, () => fetcher(client), swrOptions);
73
73
  const [dataUpdatedAt, setDataUpdatedAt] = useState(
74
- () => swr.data !== void 0 ? Date.now() : void 0
74
+ () => swrResponse.data !== void 0 ? Date.now() : void 0
75
75
  );
76
76
  useEffect(() => {
77
- if (swr.data !== void 0) {
77
+ if (swrResponse.data !== void 0) {
78
78
  setDataUpdatedAt(Date.now());
79
79
  }
80
- }, [swr.data]);
81
- const status = swr.error ? "error" : swr.isLoading ? "loading" : swr.data !== void 0 ? "success" : "idle";
82
- const refresh = useCallback(() => swr.mutate(void 0, { revalidate: true }), [swr.mutate]);
80
+ }, [swrResponse.data]);
81
+ const status = swrResponse.error ? "error" : swrResponse.isLoading ? "loading" : swrResponse.data !== void 0 ? "success" : "idle";
82
+ const refresh = useCallback(() => swrResponse.mutate(void 0, { revalidate: true }), [swrResponse.mutate]);
83
83
  return {
84
- data: swr.data,
84
+ data: swrResponse.data,
85
85
  dataUpdatedAt,
86
- error: swr.error ?? null,
86
+ error: swrResponse.error ?? null,
87
87
  isError: status === "error",
88
- isLoading: swr.isLoading,
88
+ isLoading: swrResponse.isLoading,
89
89
  isSuccess: status === "success",
90
- isValidating: swr.isValidating,
91
- mutate: swr.mutate,
90
+ isValidating: swrResponse.isValidating,
91
+ mutate: swrResponse.mutate,
92
92
  refresh,
93
93
  status
94
94
  };
95
95
  }
96
96
  __name(useSolanaRpcQuery, "useSolanaRpcQuery");
97
+ function getLatestBlockhashKey(params = {}) {
98
+ const { commitment = null, minContextSlot = null } = params;
99
+ return ["latestBlockhash", commitment, normalizeBigint(minContextSlot)];
100
+ }
101
+ __name(getLatestBlockhashKey, "getLatestBlockhashKey");
102
+ function getProgramAccountsKey(params = {}) {
103
+ const { programAddress, config } = params;
104
+ const address = programAddress ? toAddress(programAddress) : void 0;
105
+ const addressKey = address ? toAddressString(address) : null;
106
+ const configKey = stableStringify(config ?? null);
107
+ return ["programAccounts", addressKey, configKey];
108
+ }
109
+ __name(getProgramAccountsKey, "getProgramAccountsKey");
110
+ function getSimulateTransactionKey(params = {}) {
111
+ const { transaction, config } = params;
112
+ const wire = transaction ? normalizeWire(transaction) : null;
113
+ const configKey = stableStringify(config ?? null);
114
+ return ["simulateTransaction", wire, configKey];
115
+ }
116
+ __name(getSimulateTransactionKey, "getSimulateTransactionKey");
117
+ function getSignatureStatusKey(params = {}) {
118
+ const { config, signature } = params;
119
+ const signatureKey = signature?.toString() ?? null;
120
+ const configKey = JSON.stringify(config ?? null);
121
+ return ["signatureStatus", signatureKey, configKey];
122
+ }
123
+ __name(getSignatureStatusKey, "getSignatureStatusKey");
124
+ function normalizeBigint(value) {
125
+ if (value === void 0 || value === null) return null;
126
+ return typeof value === "bigint" ? value : BigInt(Math.floor(value));
127
+ }
128
+ __name(normalizeBigint, "normalizeBigint");
129
+ function normalizeWire(input) {
130
+ if (!input) return null;
131
+ if (typeof input === "string") {
132
+ return input;
133
+ }
134
+ return getBase64EncodedWireTransaction(input);
135
+ }
136
+ __name(normalizeWire, "normalizeWire");
137
+
138
+ // src/queryHooks.ts
97
139
  var DEFAULT_BLOCKHASH_REFRESH_INTERVAL = 3e4;
98
- function useLatestBlockhash(options) {
99
- const { commitment, minContextSlot, refreshInterval = DEFAULT_BLOCKHASH_REFRESH_INTERVAL, ...rest } = options ?? {};
100
- const normalizedMinContextSlot = useMemo(() => {
101
- if (minContextSlot === void 0) {
102
- return void 0;
103
- }
104
- return typeof minContextSlot === "bigint" ? minContextSlot : BigInt(Math.floor(minContextSlot));
105
- }, [minContextSlot]);
106
- const keyArgs = useMemo(
107
- () => [commitment ?? null, normalizedMinContextSlot ?? null],
108
- [commitment, normalizedMinContextSlot]
109
- );
140
+ function useLatestBlockhash(options = {}) {
141
+ const {
142
+ commitment,
143
+ minContextSlot,
144
+ refreshInterval = DEFAULT_BLOCKHASH_REFRESH_INTERVAL,
145
+ disabled = false,
146
+ swr
147
+ } = options;
110
148
  const fetcher = useCallback(
111
149
  async (client) => {
112
150
  const fallbackCommitment = commitment ?? client.store.getState().cluster.commitment;
113
151
  const plan = client.runtime.rpc.getLatestBlockhash({
114
152
  commitment: fallbackCommitment,
115
- minContextSlot: normalizedMinContextSlot
153
+ minContextSlot: normalizeMinContextSlot(minContextSlot)
116
154
  });
117
155
  return plan.send({ abortSignal: AbortSignal.timeout(15e3) });
118
156
  },
119
- [commitment, normalizedMinContextSlot]
157
+ [commitment, minContextSlot]
158
+ );
159
+ const query = useSolanaRpcQuery(
160
+ "latestBlockhash",
161
+ getLatestBlockhashKey(options),
162
+ fetcher,
163
+ {
164
+ disabled,
165
+ swr: {
166
+ refreshInterval,
167
+ ...swr
168
+ }
169
+ }
120
170
  );
121
- const query = useSolanaRpcQuery("latestBlockhash", keyArgs, fetcher, {
122
- refreshInterval,
123
- ...rest
124
- });
125
171
  return {
126
172
  ...query,
127
173
  blockhash: query.data?.value.blockhash ?? null,
@@ -131,13 +177,10 @@ function useLatestBlockhash(options) {
131
177
  }
132
178
  __name(useLatestBlockhash, "useLatestBlockhash");
133
179
  function useProgramAccounts(programAddress, options) {
134
- const { commitment, config, ...queryOptions } = options ?? {};
135
- const { disabled: disabledOption, ...restQueryOptions } = queryOptions;
136
- const address = useMemo(() => programAddress ? toAddress(programAddress) : void 0, [programAddress]);
137
- const addressKey = useMemo(() => address ? toAddressString(address) : null, [address]);
138
- const configKey = useMemo(() => stableStringify(config ?? null), [config]);
180
+ const { commitment, config, swr, disabled: disabledOption } = options ?? {};
139
181
  const fetcher = useCallback(
140
182
  async (client) => {
183
+ const address = programAddress ? toAddress(programAddress) : void 0;
141
184
  if (!address) {
142
185
  throw new Error("Provide a program address before querying program accounts.");
143
186
  }
@@ -149,13 +192,18 @@ function useProgramAccounts(programAddress, options) {
149
192
  const plan = client.runtime.rpc.getProgramAccounts(address, mergedConfig);
150
193
  return plan.send({ abortSignal: AbortSignal.timeout(2e4) });
151
194
  },
152
- [address, commitment, config]
195
+ [commitment, config, programAddress]
196
+ );
197
+ const disabled = disabledOption ?? !programAddress;
198
+ const query = useSolanaRpcQuery(
199
+ "programAccounts",
200
+ getProgramAccountsKey({ programAddress, config }),
201
+ fetcher,
202
+ {
203
+ disabled,
204
+ swr
205
+ }
153
206
  );
154
- const disabled = disabledOption ?? !address;
155
- const query = useSolanaRpcQuery("programAccounts", [addressKey, configKey], fetcher, {
156
- ...restQueryOptions,
157
- disabled
158
- });
159
207
  return {
160
208
  ...query,
161
209
  accounts: query.data ?? []
@@ -163,8 +211,7 @@ function useProgramAccounts(programAddress, options) {
163
211
  }
164
212
  __name(useProgramAccounts, "useProgramAccounts");
165
213
  function useSimulateTransaction(transaction, options) {
166
- const { commitment, config, refreshInterval, ...rest } = options ?? {};
167
- const { disabled: disabledOption, revalidateIfStale, revalidateOnFocus, ...queryOptions } = rest;
214
+ const { commitment, config, refreshInterval, disabled: disabledOption, swr } = options ?? {};
168
215
  const wire = useMemo(() => {
169
216
  if (!transaction) {
170
217
  return null;
@@ -174,7 +221,6 @@ function useSimulateTransaction(transaction, options) {
174
221
  }
175
222
  return getBase64EncodedWireTransaction(transaction);
176
223
  }, [transaction]);
177
- const configKey = useMemo(() => stableStringify(config ?? null), [config]);
178
224
  const fetcher = useCallback(
179
225
  async (client) => {
180
226
  if (!wire) {
@@ -190,19 +236,31 @@ function useSimulateTransaction(transaction, options) {
190
236
  [commitment, config, wire]
191
237
  );
192
238
  const disabled = disabledOption ?? !wire;
193
- const query = useSolanaRpcQuery("simulateTransaction", [wire, configKey], fetcher, {
194
- ...queryOptions,
195
- refreshInterval,
196
- disabled,
197
- revalidateIfStale: revalidateIfStale ?? false,
198
- revalidateOnFocus: revalidateOnFocus ?? false
199
- });
239
+ const query = useSolanaRpcQuery(
240
+ "simulateTransaction",
241
+ getSimulateTransactionKey({ transaction, config }),
242
+ fetcher,
243
+ {
244
+ disabled,
245
+ swr: {
246
+ refreshInterval,
247
+ revalidateIfStale: false,
248
+ revalidateOnFocus: false,
249
+ ...swr
250
+ }
251
+ }
252
+ );
200
253
  return {
201
254
  ...query,
202
255
  logs: query.data?.value.logs ?? []
203
256
  };
204
257
  }
205
258
  __name(useSimulateTransaction, "useSimulateTransaction");
259
+ function normalizeMinContextSlot(minContextSlot) {
260
+ if (minContextSlot === void 0) return void 0;
261
+ return typeof minContextSlot === "bigint" ? minContextSlot : BigInt(Math.floor(minContextSlot));
262
+ }
263
+ __name(normalizeMinContextSlot, "normalizeMinContextSlot");
206
264
 
207
265
  // src/hooks.ts
208
266
  function createClusterSelector() {
@@ -352,10 +410,19 @@ function useSplToken(mint, options = {}) {
352
410
  }
353
411
  return helper.fetchBalance(owner, options.commitment);
354
412
  }, [helper, owner, options.commitment]);
355
- const { data, error, isLoading, isValidating, mutate } = useSWR(balanceKey, fetchBalance, {
356
- revalidateOnFocus: options.revalidateOnFocus ?? false,
357
- suspense
358
- });
413
+ const swrOptions = useMemo(
414
+ () => ({
415
+ revalidateOnFocus: options.revalidateOnFocus ?? false,
416
+ suspense,
417
+ ...options.swr ?? {}
418
+ }),
419
+ [options.revalidateOnFocus, options.swr, suspense]
420
+ );
421
+ const { data, error, isLoading, isValidating, mutate } = useSWR(
422
+ balanceKey,
423
+ fetchBalance,
424
+ swrOptions
425
+ );
359
426
  const sessionRef = useRef(session);
360
427
  useEffect(() => {
361
428
  sessionRef.current = session;
@@ -521,24 +588,6 @@ function useBalance(addressLike, options = {}) {
521
588
  );
522
589
  }
523
590
  __name(useBalance, "useBalance");
524
- function useWalletStandardConnectors(options) {
525
- const overrides = options?.overrides;
526
- const disabled = options?.disabled ?? false;
527
- const memoisedOptions = useMemo(() => overrides ? { overrides } : void 0, [overrides]);
528
- const [connectors, setConnectors] = useState(
529
- () => disabled ? [] : getWalletStandardConnectors(memoisedOptions ?? {})
530
- );
531
- useEffect(() => {
532
- if (disabled) return;
533
- setConnectors(getWalletStandardConnectors(memoisedOptions ?? {}));
534
- const unwatch = watchWalletStandardConnectors(setConnectors, memoisedOptions ?? {});
535
- return () => {
536
- unwatch();
537
- };
538
- }, [disabled, memoisedOptions]);
539
- return connectors;
540
- }
541
- __name(useWalletStandardConnectors, "useWalletStandardConnectors");
542
591
  function useTransactionPool(config = {}) {
543
592
  const initialInstructions = useMemo(
544
593
  () => config.instructions ?? [],
@@ -546,7 +595,9 @@ function useTransactionPool(config = {}) {
546
595
  );
547
596
  const client = useSolanaClient();
548
597
  const helper = client.helpers.transaction;
549
- const blockhashMaxAgeMs = config.latestBlockhash?.refreshInterval ?? 3e4;
598
+ const swrRefreshInterval = config.latestBlockhash?.swr?.refreshInterval;
599
+ const blockhashRefreshInterval = config.latestBlockhash?.refreshInterval ?? (typeof swrRefreshInterval === "number" ? swrRefreshInterval : void 0);
600
+ const blockhashMaxAgeMs = blockhashRefreshInterval ?? 3e4;
550
601
  const controller = useMemo(
551
602
  () => createTransactionPoolController({
552
603
  blockhashMaxAgeMs,
@@ -672,10 +723,9 @@ function useSendTransaction() {
672
723
  }
673
724
  __name(useSendTransaction, "useSendTransaction");
674
725
  function useSignatureStatus(signatureInput, options = {}) {
675
- const { config, ...queryOptions } = options;
726
+ const { config, disabled: disabledOption, swr } = options;
676
727
  const signature = useMemo(() => normalizeSignature(signatureInput), [signatureInput]);
677
728
  const signatureKey = signature?.toString() ?? null;
678
- const configKey = useMemo(() => JSON.stringify(config ?? null), [config]);
679
729
  const fetcher = useCallback(
680
730
  async (client) => {
681
731
  if (!signatureKey) {
@@ -690,14 +740,14 @@ function useSignatureStatus(signatureInput, options = {}) {
690
740
  },
691
741
  [config, signature, signatureKey]
692
742
  );
693
- const disabled = queryOptions.disabled ?? !signatureKey;
743
+ const disabled = disabledOption ?? !signatureKey;
694
744
  const query = useSolanaRpcQuery(
695
745
  "signatureStatus",
696
- [signatureKey, configKey],
746
+ getSignatureStatusKey({ signature: signatureInput, config }),
697
747
  fetcher,
698
748
  {
699
- ...queryOptions,
700
- disabled
749
+ disabled,
750
+ swr
701
751
  }
702
752
  );
703
753
  const confirmationStatus = deriveConfirmationStatus(query.data ?? null);
@@ -716,14 +766,17 @@ function useWaitForSignature(signatureInput, options = {}) {
716
766
  watchCommitment,
717
767
  ...signatureStatusOptions
718
768
  } = options;
719
- const { refreshInterval, ...restStatusOptions } = signatureStatusOptions;
769
+ const { swr, ...restStatusOptions } = signatureStatusOptions;
720
770
  const subscribeCommitment = watchCommitment ?? commitment;
721
771
  const client = useSolanaClient();
722
772
  const normalizedSignature = useMemo(() => normalizeSignature(signatureInput), [signatureInput]);
723
773
  const disabled = disabledOption ?? !normalizedSignature;
724
774
  const statusQuery = useSignatureStatus(signatureInput, {
725
775
  ...restStatusOptions,
726
- refreshInterval: refreshInterval ?? 2e3,
776
+ swr: {
777
+ refreshInterval: 2e3,
778
+ ...swr
779
+ },
727
780
  disabled
728
781
  });
729
782
  const [subscriptionSettled, setSubscriptionSettled] = useState(false);
@@ -779,10 +832,11 @@ function useWaitForSignature(signatureInput, options = {}) {
779
832
  __name(useWaitForSignature, "useWaitForSignature");
780
833
  var createCache = /* @__PURE__ */ __name(() => /* @__PURE__ */ new Map(), "createCache");
781
834
  var DEFAULT_QUERY_CONFIG = Object.freeze({
782
- dedupingInterval: 1e3,
783
- focusThrottleInterval: 1e3,
835
+ dedupingInterval: 2e3,
836
+ focusThrottleInterval: 5e3,
784
837
  provider: /* @__PURE__ */ __name(() => createCache(), "provider"),
785
- revalidateOnFocus: false,
838
+ revalidateIfStale: true,
839
+ revalidateOnFocus: true,
786
840
  revalidateOnReconnect: true
787
841
  });
788
842
  function SolanaQueryProvider({
@@ -970,12 +1024,7 @@ function useWalletConnection(options = {}) {
970
1024
  const connectWallet = useConnectWallet();
971
1025
  const disconnectWallet = useDisconnectWallet();
972
1026
  const client = useSolanaClient();
973
- const shouldDiscover = !options.connectors && client.connectors.all.length === 0;
974
- const discovered = useWalletStandardConnectors({
975
- ...options.discoveryOptions,
976
- disabled: !shouldDiscover
977
- });
978
- const connectors = options.connectors ?? (client.connectors.all.length > 0 ? client.connectors.all : discovered);
1027
+ const connectors = options.connectors ?? client.connectors.all;
979
1028
  const connect = useCallback(
980
1029
  (connectorId, connectOptions) => connectWallet(connectorId, connectOptions),
981
1030
  [connectWallet]
@@ -983,6 +1032,7 @@ function useWalletConnection(options = {}) {
983
1032
  const disconnect = useCallback(() => disconnectWallet(), [disconnectWallet]);
984
1033
  const state = useMemo(() => {
985
1034
  const connectorId = "connectorId" in wallet ? wallet.connectorId : void 0;
1035
+ const currentConnector = connectorId ? connectors.find((connector) => connector.id === connectorId) : void 0;
986
1036
  const session = wallet.status === "connected" ? wallet.session : void 0;
987
1037
  const error = wallet.status === "error" ? wallet.error ?? null : null;
988
1038
  return {
@@ -991,6 +1041,7 @@ function useWalletConnection(options = {}) {
991
1041
  connecting: wallet.status === "connecting",
992
1042
  connectors,
993
1043
  connectorId,
1044
+ currentConnector,
994
1045
  disconnect,
995
1046
  error,
996
1047
  status: wallet.status,
@@ -1000,8 +1051,8 @@ function useWalletConnection(options = {}) {
1000
1051
  return state;
1001
1052
  }
1002
1053
  __name(useWalletConnection, "useWalletConnection");
1003
- function WalletConnectionManager({ children, connectors, discoveryOptions }) {
1004
- const state = useWalletConnection({ connectors, discoveryOptions });
1054
+ function WalletConnectionManager({ children, connectors }) {
1055
+ const state = useWalletConnection({ connectors });
1005
1056
  return /* @__PURE__ */ jsx(Fragment, { children: children(state) });
1006
1057
  }
1007
1058
  __name(WalletConnectionManager, "WalletConnectionManager");
@@ -1037,6 +1088,6 @@ function useWalletModalState(options = {}) {
1037
1088
  }
1038
1089
  __name(useWalletModalState, "useWalletModalState");
1039
1090
 
1040
- export { SolanaClientProvider, SolanaProvider, SolanaQueryProvider, WalletConnectionManager, useAccount, useBalance, useClientStore, useClusterState, useClusterStatus, useConnectWallet, useDisconnectWallet, useLatestBlockhash, useProgramAccounts, useSendTransaction, useSignatureStatus, useSimulateTransaction, useSolTransfer, useSolanaClient, useSplToken, useTransactionPool, useWaitForSignature, useWallet, useWalletActions, useWalletConnection, useWalletModalState, useWalletSession, useWalletStandardConnectors };
1091
+ export { SolanaClientProvider, SolanaProvider, SolanaQueryProvider, WalletConnectionManager, getLatestBlockhashKey, getProgramAccountsKey, getSignatureStatusKey, getSimulateTransactionKey, useAccount, useBalance, useClientStore, useClusterState, useClusterStatus, useConnectWallet, useDisconnectWallet, useLatestBlockhash, useProgramAccounts, useSendTransaction, useSignatureStatus, useSimulateTransaction, useSolTransfer, useSolanaClient, useSplToken, useTransactionPool, useWaitForSignature, useWallet, useWalletActions, useWalletConnection, useWalletModalState, useWalletSession };
1041
1092
  //# sourceMappingURL=index.node.mjs.map
1042
1093
  //# sourceMappingURL=index.node.mjs.map