@satoshai/kit 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6,6 +6,79 @@ var jsxRuntime = require('react/jsx-runtime');
6
6
  var transactions = require('@stacks/transactions');
7
7
  var bnsV2Sdk = require('bns-v2-sdk');
8
8
 
9
+ // src/errors.ts
10
+ var BaseError = class extends Error {
11
+ name = "StacksKitError";
12
+ /** Short, human-readable error summary without details or cause chain. */
13
+ shortMessage;
14
+ constructor(shortMessage, options) {
15
+ const message = [
16
+ shortMessage,
17
+ options?.details && `Details: ${options.details}`
18
+ ].filter(Boolean).join("\n\n");
19
+ super(message, options?.cause ? { cause: options.cause } : void 0);
20
+ this.shortMessage = shortMessage;
21
+ }
22
+ /**
23
+ * Walk the error cause chain. If `fn` is provided, returns the first error
24
+ * where `fn` returns `true`; otherwise returns the root cause.
25
+ */
26
+ walk(fn) {
27
+ return walk(this, fn);
28
+ }
29
+ };
30
+ function walk(err, fn) {
31
+ if (fn?.(err)) return err;
32
+ if (err && typeof err === "object" && "cause" in err) {
33
+ return walk(err.cause, fn);
34
+ }
35
+ return err;
36
+ }
37
+ var WalletNotConnectedError = class extends BaseError {
38
+ name = "WalletNotConnectedError";
39
+ constructor() {
40
+ super("Wallet is not connected");
41
+ }
42
+ };
43
+ var WalletNotFoundError = class extends BaseError {
44
+ name = "WalletNotFoundError";
45
+ /** The wallet ID that was not found. */
46
+ wallet;
47
+ constructor({ wallet }) {
48
+ super(`${wallet} wallet not found`, {
49
+ details: "The wallet extension may not be installed."
50
+ });
51
+ this.wallet = wallet;
52
+ }
53
+ };
54
+ var UnsupportedMethodError = class extends BaseError {
55
+ name = "UnsupportedMethodError";
56
+ /** The SIP-030 method name that is not supported. */
57
+ method;
58
+ /** The wallet that does not support the method. */
59
+ wallet;
60
+ constructor({ method, wallet }) {
61
+ super(`${method} is not supported by ${wallet} wallet`);
62
+ this.method = method;
63
+ this.wallet = wallet;
64
+ }
65
+ };
66
+ var WalletRequestError = class extends BaseError {
67
+ name = "WalletRequestError";
68
+ /** The SIP-030 method name that failed. */
69
+ method;
70
+ /** The wallet that returned the error. */
71
+ wallet;
72
+ constructor({ method, wallet, cause }) {
73
+ super(`${wallet} wallet request failed`, {
74
+ cause,
75
+ details: cause.message
76
+ });
77
+ this.method = method;
78
+ this.wallet = wallet;
79
+ }
80
+ };
81
+
9
82
  // src/constants/stacks-provider-mapping.ts
10
83
  var STACKS_TO_STACKS_CONNECT_PROVIDERS = {
11
84
  xverse: "XverseProviders.BitcoinProvider",
@@ -151,6 +224,102 @@ var extractStacksAddress = (typedProvider, addresses) => {
151
224
  `No valid Stacks address found for ${typedProvider} wallet`
152
225
  );
153
226
  };
227
+
228
+ // src/hooks/use-wallet-connect/use-wallet-connect.helpers.ts
229
+ var getWcUniversalProvider = () => window.WalletConnectProvider?.connector?.provider ?? null;
230
+ var extractStacksAddress2 = (accounts) => {
231
+ for (const entry of accounts) {
232
+ if (typeof entry === "object" && entry !== null && "address" in entry) {
233
+ return entry.address;
234
+ }
235
+ if (typeof entry === "string") {
236
+ if (entry.startsWith("S")) return entry;
237
+ if (entry.startsWith("stacks:")) return entry.split(":")[2] ?? null;
238
+ }
239
+ }
240
+ return null;
241
+ };
242
+ var PING_TIMEOUT_MS = 1e4;
243
+ var pingSession = async () => {
244
+ const wcProvider = getWcUniversalProvider();
245
+ const client = wcProvider?.client;
246
+ const session = wcProvider?.session;
247
+ if (!client || !session) return false;
248
+ try {
249
+ await Promise.race([
250
+ client.ping({ topic: session.topic }),
251
+ new Promise(
252
+ (_, reject) => setTimeout(() => reject(new Error("Ping timeout")), PING_TIMEOUT_MS)
253
+ )
254
+ ]);
255
+ return true;
256
+ } catch {
257
+ return false;
258
+ }
259
+ };
260
+
261
+ // src/hooks/use-wallet-connect/use-wallet-connect.ts
262
+ var useWalletConnect = ({
263
+ address,
264
+ provider,
265
+ onAddressChange,
266
+ onDisconnect
267
+ }) => {
268
+ react.useEffect(() => {
269
+ if (provider !== "wallet-connect" || !address) return;
270
+ let cancelled = false;
271
+ const validateSession = async () => {
272
+ const alive = await pingSession();
273
+ if (cancelled) return;
274
+ if (!alive) {
275
+ const wcProvider = getWcUniversalProvider();
276
+ try {
277
+ await wcProvider?.disconnect();
278
+ } catch {
279
+ }
280
+ connect.clearSelectedProviderId();
281
+ onDisconnect();
282
+ }
283
+ };
284
+ void validateSession();
285
+ return () => {
286
+ cancelled = true;
287
+ };
288
+ }, [provider, address, onDisconnect]);
289
+ react.useEffect(() => {
290
+ if (provider !== "wallet-connect" || !address) return;
291
+ const wcProvider = getWcUniversalProvider();
292
+ if (!wcProvider) return;
293
+ const handleDisconnect = () => {
294
+ connect.clearSelectedProviderId();
295
+ onDisconnect();
296
+ };
297
+ const handleAccountsChanged = (...args) => {
298
+ const accounts = args[0];
299
+ const newAddress = extractStacksAddress2(accounts);
300
+ if (newAddress && newAddress !== address) {
301
+ onAddressChange(newAddress);
302
+ }
303
+ };
304
+ wcProvider.on("disconnect", handleDisconnect);
305
+ wcProvider.on("accountsChanged", handleAccountsChanged);
306
+ wcProvider.on("stx_accountChange", handleAccountsChanged);
307
+ wcProvider.on("stx_accountsChanged", handleAccountsChanged);
308
+ return () => {
309
+ try {
310
+ wcProvider.off("disconnect", handleDisconnect);
311
+ wcProvider.off("accountsChanged", handleAccountsChanged);
312
+ wcProvider.off("stx_accountChange", handleAccountsChanged);
313
+ wcProvider.off("stx_accountsChanged", handleAccountsChanged);
314
+ } catch (error) {
315
+ console.error(
316
+ "Failed to remove WalletConnect listeners:",
317
+ error
318
+ );
319
+ }
320
+ };
321
+ }, [address, provider, onAddressChange, onDisconnect]);
322
+ };
154
323
  var getXverseProductInfo = async () => await window.XverseProviders?.StacksProvider?.getProductInfo?.() ?? null;
155
324
  var shouldSupportAccountChange = (version) => version !== void 0 && version !== "1.0.0";
156
325
  var waitForXverseProvider = async (maxAttempts = 10, initialDelay = 200) => {
@@ -529,6 +698,18 @@ var StacksWalletProvider = ({
529
698
  onAddressChange: handleAddressChange,
530
699
  connect: connect$1
531
700
  });
701
+ const handleWcDisconnect = react.useCallback(() => {
702
+ localStorage.removeItem(LOCAL_STORAGE_STACKS);
703
+ setAddress(void 0);
704
+ setProvider(void 0);
705
+ onDisconnect?.();
706
+ }, [onDisconnect]);
707
+ useWalletConnect({
708
+ address,
709
+ provider,
710
+ onAddressChange: handleAddressChange,
711
+ onDisconnect: handleWcDisconnect
712
+ });
532
713
  const { installed } = getStacksWallets();
533
714
  const configured = wallets ?? [...SUPPORTED_STACKS_WALLETS];
534
715
  const walletInfos = configured.map((w) => ({
@@ -685,7 +866,7 @@ var useSignMessage = () => {
685
866
  const signMessageAsync = react.useCallback(
686
867
  async (variables) => {
687
868
  if (!isConnected) {
688
- throw new Error("Wallet is not connected");
869
+ throw new WalletNotConnectedError();
689
870
  }
690
871
  setStatus("pending");
691
872
  setError(null);
@@ -694,7 +875,7 @@ var useSignMessage = () => {
694
875
  let result;
695
876
  if (provider === "okx") {
696
877
  if (!window.okxwallet) {
697
- throw new Error("OKX wallet not found");
878
+ throw new WalletNotFoundError({ wallet: "OKX" });
698
879
  }
699
880
  result = await window.okxwallet.stacks.signMessage({
700
881
  message: variables.message
@@ -711,7 +892,11 @@ var useSignMessage = () => {
711
892
  setStatus("success");
712
893
  return result;
713
894
  } catch (err) {
714
- const error2 = err instanceof Error ? err : new Error(String(err));
895
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
896
+ method: "stx_signMessage",
897
+ wallet: provider ?? "unknown",
898
+ cause: err instanceof Error ? err : new Error(String(err))
899
+ });
715
900
  setError(error2);
716
901
  setStatus("error");
717
902
  throw error2;
@@ -762,12 +947,13 @@ var useSignStructuredMessage = () => {
762
947
  const signStructuredMessageAsync = react.useCallback(
763
948
  async (variables) => {
764
949
  if (!isConnected) {
765
- throw new Error("Wallet is not connected");
950
+ throw new WalletNotConnectedError();
766
951
  }
767
952
  if (provider === "okx") {
768
- throw new Error(
769
- "Structured message signing is not supported by OKX wallet"
770
- );
953
+ throw new UnsupportedMethodError({
954
+ method: "stx_signStructuredMessage",
955
+ wallet: "OKX"
956
+ });
771
957
  }
772
958
  setStatus("pending");
773
959
  setError(null);
@@ -781,7 +967,11 @@ var useSignStructuredMessage = () => {
781
967
  setStatus("success");
782
968
  return result;
783
969
  } catch (err) {
784
- const error2 = err instanceof Error ? err : new Error(String(err));
970
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
971
+ method: "stx_signStructuredMessage",
972
+ wallet: provider ?? "unknown",
973
+ cause: err instanceof Error ? err : new Error(String(err))
974
+ });
785
975
  setError(error2);
786
976
  setStatus("error");
787
977
  throw error2;
@@ -837,12 +1027,13 @@ var useSignTransaction = () => {
837
1027
  const signTransactionAsync = react.useCallback(
838
1028
  async (variables) => {
839
1029
  if (!isConnected) {
840
- throw new Error("Wallet is not connected");
1030
+ throw new WalletNotConnectedError();
841
1031
  }
842
1032
  if (provider === "okx") {
843
- throw new Error(
844
- "Transaction signing is not supported by OKX wallet"
845
- );
1033
+ throw new UnsupportedMethodError({
1034
+ method: "stx_signTransaction",
1035
+ wallet: "OKX"
1036
+ });
846
1037
  }
847
1038
  setStatus("pending");
848
1039
  setError(null);
@@ -858,7 +1049,11 @@ var useSignTransaction = () => {
858
1049
  setStatus("success");
859
1050
  return result;
860
1051
  } catch (err) {
861
- const error2 = err instanceof Error ? err : new Error(String(err));
1052
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
1053
+ method: "stx_signTransaction",
1054
+ wallet: provider ?? "unknown",
1055
+ cause: err instanceof Error ? err : new Error(String(err))
1056
+ });
862
1057
  setError(error2);
863
1058
  setStatus("error");
864
1059
  throw error2;
@@ -920,7 +1115,7 @@ var useTransferSTX = () => {
920
1115
  const transferSTXAsync = react.useCallback(
921
1116
  async (variables) => {
922
1117
  if (!isConnected || !address) {
923
- throw new Error("Wallet is not connected");
1118
+ throw new WalletNotConnectedError();
924
1119
  }
925
1120
  setStatus("pending");
926
1121
  setError(null);
@@ -928,7 +1123,7 @@ var useTransferSTX = () => {
928
1123
  try {
929
1124
  if (provider === "okx") {
930
1125
  if (!window.okxwallet) {
931
- throw new Error("OKX wallet not found");
1126
+ throw new WalletNotFoundError({ wallet: "OKX" });
932
1127
  }
933
1128
  const response2 = await window.okxwallet.stacks.signTransaction({
934
1129
  txType: "token_transfer",
@@ -963,7 +1158,11 @@ var useTransferSTX = () => {
963
1158
  setStatus("success");
964
1159
  return response.txid;
965
1160
  } catch (err) {
966
- const error2 = err instanceof Error ? err : new Error(String(err));
1161
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
1162
+ method: "stx_transferStx",
1163
+ wallet: provider ?? "unknown",
1164
+ cause: err instanceof Error ? err : new Error(String(err))
1165
+ });
967
1166
  setError(error2);
968
1167
  setStatus("error");
969
1168
  throw error2;
@@ -1151,7 +1350,7 @@ var useWriteContract = () => {
1151
1350
  const writeContractAsync = react.useCallback(
1152
1351
  async (variables) => {
1153
1352
  if (!isConnected || !address) {
1154
- throw new Error("Wallet is not connected");
1353
+ throw new WalletNotConnectedError();
1155
1354
  }
1156
1355
  setStatus("pending");
1157
1356
  setError(null);
@@ -1160,7 +1359,7 @@ var useWriteContract = () => {
1160
1359
  try {
1161
1360
  if (provider === "okx") {
1162
1361
  if (!window.okxwallet) {
1163
- throw new Error("OKX wallet not found");
1362
+ throw new WalletNotFoundError({ wallet: "OKX" });
1164
1363
  }
1165
1364
  const response2 = await window.okxwallet.stacks.signTransaction({
1166
1365
  contractAddress: variables.address,
@@ -1195,7 +1394,11 @@ var useWriteContract = () => {
1195
1394
  setStatus("success");
1196
1395
  return response.txid;
1197
1396
  } catch (err) {
1198
- const error2 = err instanceof Error ? err : new Error(String(err));
1397
+ const error2 = err instanceof BaseError ? err : new WalletRequestError({
1398
+ method: "stx_callContract",
1399
+ wallet: provider ?? "unknown",
1400
+ cause: err instanceof Error ? err : new Error(String(err))
1401
+ });
1199
1402
  setError(error2);
1200
1403
  setStatus("error");
1201
1404
  throw error2;
@@ -1280,8 +1483,13 @@ function createContractConfig(config) {
1280
1483
  return config;
1281
1484
  }
1282
1485
 
1486
+ exports.BaseError = BaseError;
1283
1487
  exports.SUPPORTED_STACKS_WALLETS = SUPPORTED_STACKS_WALLETS;
1284
1488
  exports.StacksWalletProvider = StacksWalletProvider;
1489
+ exports.UnsupportedMethodError = UnsupportedMethodError;
1490
+ exports.WalletNotConnectedError = WalletNotConnectedError;
1491
+ exports.WalletNotFoundError = WalletNotFoundError;
1492
+ exports.WalletRequestError = WalletRequestError;
1285
1493
  exports.createContractConfig = createContractConfig;
1286
1494
  exports.getLocalStorageWallet = getLocalStorageWallet;
1287
1495
  exports.getNetworkFromAddress = getNetworkFromAddress;