@thru/react-sdk 0.0.4 → 0.0.6

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.d.ts CHANGED
@@ -1,19 +1,21 @@
1
1
  import { BrowserSDK, BrowserSDKConfig, ConnectOptions } from '@thru/browser-sdk';
2
2
  export { BrowserSDK, BrowserSDKConfig, ConnectOptions, ErrorCode, SDKEvent } from '@thru/browser-sdk';
3
3
  import * as _thru_chain_interfaces from '@thru/chain-interfaces';
4
- import { WalletAddress, IThruChain, ConnectResult } from '@thru/chain-interfaces';
5
- export { ConnectResult, IThruChain, SignMessageParams, SignMessageResult, WalletAddress } from '@thru/chain-interfaces';
6
- import { Thru } from '@thru/thru-sdk';
4
+ import { WalletAccount, IThruChain, ConnectResult } from '@thru/chain-interfaces';
5
+ export { ConnectResult, IThruChain, SignMessageParams, SignMessageResult, WalletAccount } from '@thru/chain-interfaces';
6
+ import { Thru } from '@thru/thru-sdk/client';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
8
  import { ReactNode } from 'react';
9
9
 
10
10
  interface ThruContextValue {
11
11
  wallet: BrowserSDK | null;
12
12
  isConnected: boolean;
13
- addresses: WalletAddress[];
13
+ accounts: WalletAccount[];
14
14
  isConnecting: boolean;
15
15
  error: Error | null;
16
16
  thru: Thru | null;
17
+ selectedAccount: WalletAccount | null;
18
+ selectAccount: (account: WalletAccount) => Promise<void>;
17
19
  }
18
20
 
19
21
  interface ThruProviderProps {
@@ -26,6 +28,20 @@ interface ThruProviderProps {
26
28
  */
27
29
  declare function ThruProvider({ children, config }: ThruProviderProps): react_jsx_runtime.JSX.Element;
28
30
 
31
+ interface UseAccountsResult {
32
+ accounts: WalletAccount[];
33
+ selectedAccount: WalletAccount | null;
34
+ isConnected: boolean;
35
+ isConnecting: boolean;
36
+ }
37
+ interface UseAccountsOptions {
38
+ onAccountSelect?: (account: WalletAccount) => void;
39
+ }
40
+ /**
41
+ * useAccounts - Exposes connected wallet accounts and selection helpers.
42
+ */
43
+ declare function useAccounts(options?: UseAccountsOptions): UseAccountsResult;
44
+
29
45
  /**
30
46
  * useThru - Access the Thru SDK context
31
47
  * Must be used within a ThruProvider
@@ -38,10 +54,13 @@ declare function useThru(): ThruContextValue;
38
54
  */
39
55
  declare function useWallet(): {
40
56
  wallet: IThruChain | undefined;
41
- addresses: _thru_chain_interfaces.WalletAddress[];
57
+ accounts: _thru_chain_interfaces.WalletAccount[];
42
58
  connect: (options?: ConnectOptions) => Promise<ConnectResult>;
43
59
  disconnect: () => Promise<void>;
44
60
  isConnected: boolean;
61
+ isConnecting: boolean;
62
+ selectedAccount: _thru_chain_interfaces.WalletAccount | null;
63
+ selectAccount: (account: _thru_chain_interfaces.WalletAccount) => Promise<void>;
45
64
  };
46
65
 
47
- export { type ThruContextValue, ThruProvider, type ThruProviderProps, useThru, useWallet };
66
+ export { type ThruContextValue, ThruProvider, type ThruProviderProps, type UseAccountsOptions, type UseAccountsResult, useAccounts, useThru, useWallet };
package/dist/index.js CHANGED
@@ -1,29 +1,43 @@
1
1
  "use client";
2
2
  import { BrowserSDK } from '@thru/browser-sdk';
3
3
  export { BrowserSDK, ErrorCode } from '@thru/browser-sdk';
4
- import { createContext, useState, useEffect, useContext, useRef } from 'react';
4
+ import { createContext, useState, useEffect, useCallback, useContext, useMemo, useRef } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
 
7
7
  var defaultContextValue = {
8
8
  wallet: null,
9
9
  isConnected: false,
10
- addresses: [],
10
+ accounts: [],
11
11
  isConnecting: false,
12
12
  error: null,
13
- thru: null
13
+ thru: null,
14
+ selectedAccount: null,
15
+ selectAccount: async () => void 0
14
16
  };
15
17
  var ThruContext = createContext(defaultContextValue);
16
18
  function ThruProvider({ children, config }) {
17
19
  const [sdk, setSdk] = useState(null);
18
20
  const [thru, setThru] = useState(null);
19
21
  const [isConnected, setIsConnected] = useState(false);
20
- const [addresses, setAddresses] = useState([]);
22
+ const [accounts, setAccounts] = useState([]);
21
23
  const [isConnecting, setIsConnecting] = useState(false);
22
24
  const [error, setError] = useState(null);
25
+ const [selectedAccount, setSelectedAccount] = useState(null);
23
26
  useEffect(() => {
24
27
  const sdkInstance = new BrowserSDK(config);
25
28
  setSdk(sdkInstance);
26
29
  setThru(sdkInstance.getThru());
30
+ const updateAccountsFromSdk = () => {
31
+ setAccounts(sdkInstance.getAccounts());
32
+ };
33
+ const updateSelectedAccount = (account) => {
34
+ if (account) {
35
+ setSelectedAccount(account);
36
+ return;
37
+ }
38
+ const fallback = sdkInstance.getSelectedAccount() ?? sdkInstance.getAccounts()[0] ?? null;
39
+ setSelectedAccount(fallback);
40
+ };
27
41
  sdkInstance.initialize().catch((err) => {
28
42
  console.error("Failed to initialize SDK:", err);
29
43
  setError(err);
@@ -34,37 +48,71 @@ function ThruProvider({ children, config }) {
34
48
  setError(null);
35
49
  } else {
36
50
  setIsConnected(true);
37
- setAddresses(sdkInstance.getAddresses());
51
+ updateAccountsFromSdk();
38
52
  setIsConnecting(false);
39
53
  setError(null);
54
+ if (result?.accounts?.length) {
55
+ setSelectedAccount(result.accounts[0]);
56
+ } else {
57
+ updateSelectedAccount();
58
+ }
40
59
  }
41
60
  };
42
- const handleDisconnect = () => {
61
+ const resetData = () => {
43
62
  setIsConnected(false);
44
- setAddresses([]);
63
+ setAccounts([]);
45
64
  setIsConnecting(false);
65
+ setSelectedAccount(null);
66
+ };
67
+ const handleDisconnect = () => {
68
+ resetData();
46
69
  };
47
70
  const handleError = (err) => {
48
71
  setError(err.error || new Error("Unknown error"));
49
72
  setIsConnecting(false);
50
73
  };
51
74
  const handleLock = () => {
52
- setIsConnected(false);
53
- setAddresses([]);
54
- setIsConnecting(false);
75
+ resetData();
76
+ };
77
+ const handleAccountChanged = (account) => {
78
+ updateAccountsFromSdk();
79
+ updateSelectedAccount(account ?? void 0);
55
80
  };
56
81
  sdkInstance.on("connect", handleConnect);
57
82
  sdkInstance.on("disconnect", handleDisconnect);
58
83
  sdkInstance.on("error", handleError);
59
84
  sdkInstance.on("lock", handleLock);
85
+ sdkInstance.on("accountChanged", handleAccountChanged);
60
86
  return () => {
61
87
  sdkInstance.off("connect", handleConnect);
62
88
  sdkInstance.off("disconnect", handleDisconnect);
63
89
  sdkInstance.off("error", handleError);
64
90
  sdkInstance.off("lock", handleLock);
91
+ sdkInstance.off("accountChanged", handleAccountChanged);
65
92
  sdkInstance.destroy();
66
93
  };
67
94
  }, []);
95
+ const selectAccount = useCallback(async (account) => {
96
+ if (!sdk) {
97
+ throw new Error("BrowserSDK not initialized");
98
+ }
99
+ try {
100
+ const updated = await sdk.selectAccount(account.address);
101
+ setSelectedAccount(updated);
102
+ setAccounts((prev) => {
103
+ const index = prev.findIndex((acc) => acc.address === updated.address);
104
+ if (index >= 0) {
105
+ const next = [...prev];
106
+ next[index] = updated;
107
+ return next;
108
+ }
109
+ return [...prev, updated];
110
+ });
111
+ } catch (err) {
112
+ setError(err instanceof Error ? err : new Error("Failed to select account"));
113
+ throw err;
114
+ }
115
+ }, [sdk]);
68
116
  return /* @__PURE__ */ jsx(
69
117
  ThruContext.Provider,
70
118
  {
@@ -72,9 +120,11 @@ function ThruProvider({ children, config }) {
72
120
  thru,
73
121
  wallet: sdk,
74
122
  isConnected,
75
- addresses,
123
+ accounts,
76
124
  isConnecting,
77
- error
125
+ error,
126
+ selectedAccount,
127
+ selectAccount
78
128
  },
79
129
  children
80
130
  }
@@ -84,6 +134,26 @@ function useThru() {
84
134
  const context = useContext(ThruContext);
85
135
  return context;
86
136
  }
137
+
138
+ // src/hooks/useAccounts.ts
139
+ function useAccounts(options) {
140
+ const { accounts, selectedAccount, isConnected, isConnecting } = useThru();
141
+ const externalOnSelect = options?.onAccountSelect;
142
+ useEffect(() => {
143
+ if (selectedAccount) {
144
+ externalOnSelect?.(selectedAccount);
145
+ }
146
+ }, [externalOnSelect, selectedAccount]);
147
+ return useMemo(
148
+ () => ({
149
+ accounts,
150
+ selectedAccount,
151
+ isConnected,
152
+ isConnecting
153
+ }),
154
+ [accounts, selectedAccount, isConnected, isConnecting]
155
+ );
156
+ }
87
157
  function waitForWallet(getWallet, timeout = 5e3, interval = 100) {
88
158
  return new Promise((resolve, reject) => {
89
159
  const start = Date.now();
@@ -97,7 +167,7 @@ function waitForWallet(getWallet, timeout = 5e3, interval = 100) {
97
167
  });
98
168
  }
99
169
  function useWallet() {
100
- const { wallet, isConnected, addresses } = useThru();
170
+ const { wallet, isConnected, accounts, selectedAccount, selectAccount, isConnecting } = useThru();
101
171
  const walletRef = useRef(wallet);
102
172
  useEffect(() => {
103
173
  walletRef.current = wallet;
@@ -120,13 +190,16 @@ function useWallet() {
120
190
  };
121
191
  return {
122
192
  wallet: wallet?.thru,
123
- addresses,
193
+ accounts,
124
194
  connect,
125
195
  disconnect,
126
- isConnected: isConnected && !!wallet
196
+ isConnected: isConnected && !!wallet,
197
+ isConnecting,
198
+ selectedAccount,
199
+ selectAccount
127
200
  };
128
201
  }
129
202
 
130
- export { ThruProvider, useThru, useWallet };
203
+ export { ThruProvider, useAccounts, useThru, useWallet };
131
204
  //# sourceMappingURL=index.js.map
132
205
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ThruContext.ts","../src/ThruProvider.tsx","../src/hooks/useThru.ts","../src/hooks/useWallet.ts"],"names":["useEffect"],"mappings":";;;;;AAcA,IAAM,mBAAA,GAAwC;AAAA,EAC1C,MAAA,EAAQ,IAAA;AAAA,EACR,WAAA,EAAa,KAAA;AAAA,EACb,WAAW,EAAC;AAAA,EACZ,YAAA,EAAc,KAAA;AAAA,EACd,KAAA,EAAO,IAAA;AAAA,EACP,IAAA,EAAM;AACV,CAAA;AAEO,IAAM,WAAA,GAAc,cAAgC,mBAAmB,CAAA;ACPvE,SAAS,YAAA,CAAa,EAAE,QAAA,EAAU,MAAA,EAAO,EAAsB;AACpE,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAI,SAA4B,IAAI,CAAA;AACtD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAsB,IAAI,CAAA;AAClD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,KAAK,CAAA;AACpD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,QAAA,CAA0B,EAAE,CAAA;AAC9D,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA;AAErD,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,MAAM,WAAA,GAAc,IAAI,UAAA,CAAW,MAAM,CAAA;AACzC,IAAA,MAAA,CAAO,WAAW,CAAA;AAElB,IAAA,OAAA,CAAQ,WAAA,CAAY,SAAS,CAAA;AAG7B,IAAA,WAAA,CAAY,UAAA,EAAW,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACtC,MAAA,OAAA,CAAQ,KAAA,CAAM,6BAA6B,GAAG,CAAA;AAC9C,MAAA,QAAA,CAAS,GAAG,CAAA;AAAA,IACd,CAAC,CAAA;AAGD,IAAA,MAAM,aAAA,GAAgB,CAAC,MAAA,KAAgB;AAErC,MAAA,IAAI,MAAA,CAAO,WAAW,YAAA,EAAc;AAClC,QAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,QAAA,QAAA,CAAS,IAAI,CAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,cAAA,CAAe,IAAI,CAAA;AACnB,QAAA,YAAA,CAAa,WAAA,CAAY,cAAc,CAAA;AACvC,QAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,QAAA,QAAA,CAAS,IAAI,CAAA;AAAA,MACf;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,mBAAmB,MAAM;AAC7B,MAAA,cAAA,CAAe,KAAK,CAAA;AACpB,MAAA,YAAA,CAAa,EAAE,CAAA;AACf,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB,CAAA;AAEA,IAAA,MAAM,WAAA,GAAc,CAAC,GAAA,KAAa;AAChC,MAAA,QAAA,CAAS,GAAA,CAAI,KAAA,IAAS,IAAI,KAAA,CAAM,eAAe,CAAC,CAAA;AAChD,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB,CAAA;AAEA,IAAA,MAAM,aAAa,MAAM;AACvB,MAAA,cAAA,CAAe,KAAK,CAAA;AACpB,MAAA,YAAA,CAAa,EAAE,CAAA;AACf,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB,CAAA;AAEA,IAAA,WAAA,CAAY,EAAA,CAAG,WAAW,aAAa,CAAA;AACvC,IAAA,WAAA,CAAY,EAAA,CAAG,cAAc,gBAAgB,CAAA;AAC7C,IAAA,WAAA,CAAY,EAAA,CAAG,SAAS,WAAW,CAAA;AACnC,IAAA,WAAA,CAAY,EAAA,CAAG,QAAQ,UAAU,CAAA;AAGjC,IAAA,OAAO,MAAM;AACX,MAAA,WAAA,CAAY,GAAA,CAAI,WAAW,aAAa,CAAA;AACxC,MAAA,WAAA,CAAY,GAAA,CAAI,cAAc,gBAAgB,CAAA;AAC9C,MAAA,WAAA,CAAY,GAAA,CAAI,SAAS,WAAW,CAAA;AACpC,MAAA,WAAA,CAAY,GAAA,CAAI,QAAQ,UAAU,CAAA;AAClC,MAAA,WAAA,CAAY,OAAA,EAAQ;AAAA,IACtB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,uBACE,GAAA;AAAA,IAAC,WAAA,CAAY,QAAA;AAAA,IAAZ;AAAA,MACC,KAAA,EAAO;AAAA,QACL,IAAA;AAAA,QACA,MAAA,EAAQ,GAAA;AAAA,QACR,WAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;AC1FO,SAAS,OAAA,GAAU;AACtB,EAAA,MAAM,OAAA,GAAU,WAAW,WAAW,CAAA;AACtC,EAAA,OAAO,OAAA;AACX;ACLA,SAAS,aAAA,CAAc,SAAA,EAAoC,OAAA,GAAU,GAAA,EAAM,WAAW,GAAA,EAA0B;AAC9G,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,MAAM,MAAM,SAAA,EAAU;AACtB,MAAA,IAAI,GAAA,EAAK,OAAO,OAAA,CAAQ,GAAG,CAAA;AAC3B,MAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA,GAAQ,OAAA,SAAgB,MAAA,CAAO,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AACxF,MAAA,UAAA,CAAW,OAAO,QAAQ,CAAA;AAAA,IAC5B,CAAA;AACA,IAAA,KAAA,EAAM;AAAA,EACR,CAAC,CAAA;AACH;AAMO,SAAS,SAAA,GAAY;AAC1B,EAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAa,SAAA,KAAc,OAAA,EAAQ;AACnD,EAAA,MAAM,SAAA,GAAY,OAAO,MAAM,CAAA;AAE/B,EAAAA,UAAU,MAAM;AACd,IAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAAA,EACtB,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,aAAa,YAA2B;AAC5C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,qBAAqB,CAAA;AAAA,IACvC;AACA,IAAA,MAAM,OAAO,UAAA,EAAW;AAAA,EAC1B,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,OAAO,OAAA,KAAqD;AAC1E,IAAA,IAAI;AACF,MAAA,MAAM,WACJ,SAAA,CAAU,OAAA,IAAY,MAAM,aAAA,CAAc,MAAM,UAAU,OAAO,CAAA;AACnE,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,OAAA,CAAQ,OAAO,CAAA;AAC7C,MAAA,OAAO,MAAA;AAAA,IACT,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,KAAA,GAAQ,GAAA;AACd,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,QAAQ,MAAA,EAAQ,IAAA;AAAA,IAChB,SAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,WAAA,EAAa,WAAA,IAAe,CAAC,CAAC;AAAA,GAChC;AACF","file":"index.js","sourcesContent":["import { BrowserSDK } from \"@thru/browser-sdk\";\nimport { WalletAddress } from \"@thru/chain-interfaces\";\nimport { Thru } from \"@thru/thru-sdk\";\nimport { createContext } from \"react\";\n\nexport interface ThruContextValue {\n wallet: BrowserSDK | null;\n isConnected: boolean;\n addresses: WalletAddress[];\n isConnecting: boolean;\n error: Error | null;\n thru: Thru | null;\n}\n\nconst defaultContextValue: ThruContextValue = {\n wallet: null,\n isConnected: false,\n addresses: [],\n isConnecting: false,\n error: null,\n thru: null,\n};\n\nexport const ThruContext = createContext<ThruContextValue>(defaultContextValue);\n","'use client';\n\nimport { BrowserSDK, type BrowserSDKConfig, type WalletAddress } from '@thru/browser-sdk';\nimport type { Thru } from '@thru/thru-sdk';\nimport { ReactNode, useEffect, useState } from 'react';\nimport { ThruContext } from './ThruContext';\n\nexport interface ThruProviderProps {\n children: ReactNode;\n config: BrowserSDKConfig;\n}\n\n/**\n * ThruProvider - React context provider for Thru Wallet SDK\n * Wraps the BrowserSDK and exposes state via context\n */\nexport function ThruProvider({ children, config }: ThruProviderProps) {\n const [sdk, setSdk] = useState<BrowserSDK | null>(null);\n const [thru, setThru] = useState<Thru | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [addresses, setAddresses] = useState<WalletAddress[]>([]);\n const [isConnecting, setIsConnecting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n // Create SDK instance\n const sdkInstance = new BrowserSDK(config);\n setSdk(sdkInstance);\n\n setThru(sdkInstance.getThru());\n\n // Initialize SDK (creates iframe)\n sdkInstance.initialize().catch((err) => {\n console.error('Failed to initialize SDK:', err);\n setError(err);\n });\n\n // Listen to SDK events\n const handleConnect = (result: any) => {\n // Check if this is the initial \"connecting\" status or actual connection\n if (result.status === 'connecting') {\n setIsConnecting(true);\n setError(null);\n } else {\n setIsConnected(true);\n setAddresses(sdkInstance.getAddresses());\n setIsConnecting(false);\n setError(null);\n }\n };\n\n const handleDisconnect = () => {\n setIsConnected(false);\n setAddresses([]);\n setIsConnecting(false);\n };\n\n const handleError = (err: any) => {\n setError(err.error || new Error('Unknown error'));\n setIsConnecting(false);\n };\n\n const handleLock = () => {\n setIsConnected(false);\n setAddresses([]);\n setIsConnecting(false);\n };\n\n sdkInstance.on('connect', handleConnect);\n sdkInstance.on('disconnect', handleDisconnect);\n sdkInstance.on('error', handleError);\n sdkInstance.on('lock', handleLock);\n\n // Cleanup on unmount\n return () => {\n sdkInstance.off('connect', handleConnect);\n sdkInstance.off('disconnect', handleDisconnect);\n sdkInstance.off('error', handleError);\n sdkInstance.off('lock', handleLock);\n sdkInstance.destroy();\n };\n }, []); // Empty dependency array - only create SDK once\n\n return (\n <ThruContext.Provider\n value={{\n thru,\n wallet: sdk,\n isConnected,\n addresses,\n isConnecting,\n error,\n }}\n >\n {children}\n </ThruContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { ThruContext } from \"../ThruContext\";\n\n/**\n * useThru - Access the Thru SDK context\n * Must be used within a ThruProvider\n */\nexport function useThru() {\n const context = useContext(ThruContext);\n return context;\n}","import { BrowserSDK, ConnectOptions } from '@thru/browser-sdk';\nimport type { ConnectResult, IThruChain } from '@thru/chain-interfaces';\nimport { useEffect, useRef } from 'react';\nimport { useThru } from './useThru';\n\nfunction waitForWallet(getWallet: () => BrowserSDK | null, timeout = 5000, interval = 100): Promise<BrowserSDK> {\n return new Promise((resolve, reject) => {\n const start = Date.now();\n const check = () => {\n const sdk = getWallet();\n if (sdk) return resolve(sdk);\n if (Date.now() - start > timeout) return reject(new Error('SDK not initialized in time'));\n setTimeout(check, interval);\n };\n check();\n });\n}\n\n/**\n * useThruChain - Hook for accessing the Thru chain API exposed by the Browser SDK.\n * Returns the chain instance (if available) and a boolean indicating readiness.\n */\nexport function useWallet() {\n const { wallet, isConnected, addresses } = useThru();\n const walletRef = useRef(wallet);\n\n useEffect(() => {\n walletRef.current = wallet;\n }, [wallet]);\n\n const disconnect = async (): Promise<void> => {\n if (!wallet) {\n throw new Error('SDK not initialized');\n }\n await wallet.disconnect();\n };\n\n const connect = async (options?: ConnectOptions): Promise<ConnectResult> => {\n try {\n const readySdk =\n walletRef.current ?? (await waitForWallet(() => walletRef.current));\n const result = await readySdk.connect(options);\n return result;\n } catch (err) {\n const error = err as Error;\n throw error;\n }\n };\n\n return {\n wallet: wallet?.thru as IThruChain | undefined,\n addresses,\n connect,\n disconnect,\n isConnected: isConnected && !!wallet,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/ThruContext.ts","../src/ThruProvider.tsx","../src/hooks/useThru.ts","../src/hooks/useAccounts.ts","../src/hooks/useWallet.ts"],"names":["useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { BrowserSDK } from \"@thru/browser-sdk\";\nimport { WalletAccount } from \"@thru/chain-interfaces\";\nimport { Thru } from \"@thru/thru-sdk/client\";\nimport { createContext } from \"react\";\n\nexport interface ThruContextValue {\n wallet: BrowserSDK | null;\n isConnected: boolean;\n accounts: WalletAccount[];\n isConnecting: boolean;\n error: Error | null;\n thru: Thru | null;\n selectedAccount: WalletAccount | null;\n selectAccount: (account: WalletAccount) => Promise<void>;\n}\n\nconst defaultContextValue: ThruContextValue = {\n wallet: null,\n isConnected: false,\n accounts: [],\n isConnecting: false,\n error: null,\n thru: null,\n selectedAccount: null,\n selectAccount: async () => undefined,\n};\n\nexport const ThruContext = createContext<ThruContextValue>(defaultContextValue);\n","'use client';\n\nimport { BrowserSDK, type BrowserSDKConfig, type WalletAccount } from '@thru/browser-sdk';\nimport type { Thru } from '@thru/thru-sdk/client';\nimport { ReactNode, useCallback, useEffect, useState } from 'react';\nimport { ThruContext } from './ThruContext';\n\nexport interface ThruProviderProps {\n children: ReactNode;\n config: BrowserSDKConfig;\n}\n\n/**\n * ThruProvider - React context provider for Thru Wallet SDK\n * Wraps the BrowserSDK and exposes state via context\n */\nexport function ThruProvider({ children, config }: ThruProviderProps) {\n const [sdk, setSdk] = useState<BrowserSDK | null>(null);\n const [thru, setThru] = useState<Thru | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [accounts, setAccounts] = useState<WalletAccount[]>([]);\n const [isConnecting, setIsConnecting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [selectedAccount, setSelectedAccount] = useState<WalletAccount | null>(null);\n\n useEffect(() => {\n // Create SDK instance\n const sdkInstance = new BrowserSDK(config);\n setSdk(sdkInstance);\n setThru(sdkInstance.getThru());\n\n const updateAccountsFromSdk = () => {\n setAccounts(sdkInstance.getAccounts());\n };\n\n const updateSelectedAccount = (account?: WalletAccount | null) => {\n if (account) {\n setSelectedAccount(account);\n return;\n }\n const fallback = sdkInstance.getSelectedAccount() ?? sdkInstance.getAccounts()[0] ?? null;\n setSelectedAccount(fallback);\n };\n\n sdkInstance.initialize().catch((err) => {\n console.error('Failed to initialize SDK:', err);\n setError(err);\n });\n\n // Listen to SDK events\n const handleConnect = (result: any) => {\n // Check if this is the initial \"connecting\" status or actual connection\n if (result.status === 'connecting') {\n setIsConnecting(true);\n setError(null);\n } else {\n setIsConnected(true);\n updateAccountsFromSdk();\n setIsConnecting(false);\n setError(null);\n if (result?.accounts?.length) {\n setSelectedAccount(result.accounts[0]);\n } else {\n updateSelectedAccount();\n }\n }\n };\n\n const resetData = () => {\n setIsConnected(false);\n setAccounts([]);\n setIsConnecting(false);\n setSelectedAccount(null);\n };\n\n const handleDisconnect = () => {\n resetData();\n };\n\n const handleError = (err: any) => {\n setError(err.error || new Error('Unknown error'));\n setIsConnecting(false);\n };\n\n const handleLock = () => {\n resetData();\n };\n\n const handleAccountChanged = (account: WalletAccount | null | undefined) => {\n updateAccountsFromSdk();\n updateSelectedAccount(account ?? undefined);\n };\n\n sdkInstance.on('connect', handleConnect);\n sdkInstance.on('disconnect', handleDisconnect);\n sdkInstance.on('error', handleError);\n sdkInstance.on('lock', handleLock);\n sdkInstance.on('accountChanged', handleAccountChanged);\n\n // Cleanup on unmount\n return () => {\n sdkInstance.off('connect', handleConnect);\n sdkInstance.off('disconnect', handleDisconnect);\n sdkInstance.off('error', handleError);\n sdkInstance.off('lock', handleLock);\n sdkInstance.off('accountChanged', handleAccountChanged);\n sdkInstance.destroy();\n };\n }, []); // Empty dependency array - only create SDK once\n\n const selectAccount = useCallback(async (account: WalletAccount) => {\n if (!sdk) {\n throw new Error('BrowserSDK not initialized');\n }\n\n try {\n const updated = await sdk.selectAccount(account.address);\n setSelectedAccount(updated);\n setAccounts(prev => {\n const index = prev.findIndex(acc => acc.address === updated.address);\n if (index >= 0) {\n const next = [...prev];\n next[index] = updated;\n return next;\n }\n return [...prev, updated];\n });\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to select account'));\n throw err;\n }\n }, [sdk]);\n\n return (\n <ThruContext.Provider\n value={{\n thru,\n wallet: sdk,\n isConnected,\n accounts,\n isConnecting,\n error,\n selectedAccount,\n selectAccount,\n }}\n >\n {children}\n </ThruContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { ThruContext } from \"../ThruContext\";\n\n/**\n * useThru - Access the Thru SDK context\n * Must be used within a ThruProvider\n */\nexport function useThru() {\n const context = useContext(ThruContext);\n return context;\n}","import type { WalletAccount } from '@thru/chain-interfaces';\nimport { useEffect, useMemo } from 'react';\nimport { useThru } from './useThru';\n\nexport interface UseAccountsResult {\n accounts: WalletAccount[];\n selectedAccount: WalletAccount | null;\n isConnected: boolean;\n isConnecting: boolean;\n}\n\nexport interface UseAccountsOptions {\n onAccountSelect?: (account: WalletAccount) => void;\n}\n\n/**\n * useAccounts - Exposes connected wallet accounts and selection helpers.\n */\nexport function useAccounts(options?: UseAccountsOptions): UseAccountsResult {\n const { accounts, selectedAccount, isConnected, isConnecting } = useThru();\n const externalOnSelect = options?.onAccountSelect;\n\n useEffect(() => {\n if (selectedAccount) {\n externalOnSelect?.(selectedAccount);\n }\n }, [externalOnSelect, selectedAccount]);\n\n return useMemo(\n () => ({\n accounts,\n selectedAccount,\n isConnected,\n isConnecting,\n }),\n [accounts, selectedAccount, isConnected, isConnecting]\n );\n}\n","import { BrowserSDK, ConnectOptions } from '@thru/browser-sdk';\nimport type { ConnectResult, IThruChain } from '@thru/chain-interfaces';\nimport { useEffect, useRef } from 'react';\nimport { useThru } from './useThru';\n\nfunction waitForWallet(getWallet: () => BrowserSDK | null, timeout = 5000, interval = 100): Promise<BrowserSDK> {\n return new Promise((resolve, reject) => {\n const start = Date.now();\n const check = () => {\n const sdk = getWallet();\n if (sdk) return resolve(sdk);\n if (Date.now() - start > timeout) return reject(new Error('SDK not initialized in time'));\n setTimeout(check, interval);\n };\n check();\n });\n}\n\n/**\n * useThruChain - Hook for accessing the Thru chain API exposed by the Browser SDK.\n * Returns the chain instance (if available) and a boolean indicating readiness.\n */\nexport function useWallet() {\n const { wallet, isConnected, accounts, selectedAccount, selectAccount, isConnecting } = useThru();\n const walletRef = useRef(wallet);\n\n useEffect(() => {\n walletRef.current = wallet;\n }, [wallet]);\n\n const disconnect = async (): Promise<void> => {\n if (!wallet) {\n throw new Error('SDK not initialized');\n }\n await wallet.disconnect();\n };\n\n const connect = async (options?: ConnectOptions): Promise<ConnectResult> => {\n try {\n const readySdk =\n walletRef.current ?? (await waitForWallet(() => walletRef.current));\n const result = await readySdk.connect(options);\n return result;\n } catch (err) {\n const error = err as Error;\n throw error;\n }\n };\n\n return {\n wallet: wallet?.thru as IThruChain | undefined,\n accounts,\n connect,\n disconnect,\n isConnected: isConnected && !!wallet,\n isConnecting,\n selectedAccount,\n selectAccount,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thru/react-sdk",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -11,9 +11,9 @@
11
11
  }
12
12
  },
13
13
  "dependencies": {
14
- "@thru/browser-sdk": "0.0.4",
15
- "@thru/chain-interfaces": "0.0.4",
16
- "@thru/thru-sdk": "0.0.4"
14
+ "@thru/browser-sdk": "0.0.6",
15
+ "@thru/thru-sdk": "0.0.6",
16
+ "@thru/chain-interfaces": "0.0.6"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "react": "^18.0.0 || ^19.0.0",
@@ -1,24 +1,28 @@
1
1
  import { BrowserSDK } from "@thru/browser-sdk";
2
- import { WalletAddress } from "@thru/chain-interfaces";
3
- import { Thru } from "@thru/thru-sdk";
2
+ import { WalletAccount } from "@thru/chain-interfaces";
3
+ import { Thru } from "@thru/thru-sdk/client";
4
4
  import { createContext } from "react";
5
5
 
6
6
  export interface ThruContextValue {
7
7
  wallet: BrowserSDK | null;
8
8
  isConnected: boolean;
9
- addresses: WalletAddress[];
9
+ accounts: WalletAccount[];
10
10
  isConnecting: boolean;
11
11
  error: Error | null;
12
12
  thru: Thru | null;
13
+ selectedAccount: WalletAccount | null;
14
+ selectAccount: (account: WalletAccount) => Promise<void>;
13
15
  }
14
16
 
15
17
  const defaultContextValue: ThruContextValue = {
16
18
  wallet: null,
17
19
  isConnected: false,
18
- addresses: [],
20
+ accounts: [],
19
21
  isConnecting: false,
20
22
  error: null,
21
23
  thru: null,
24
+ selectedAccount: null,
25
+ selectAccount: async () => undefined,
22
26
  };
23
27
 
24
28
  export const ThruContext = createContext<ThruContextValue>(defaultContextValue);
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { BrowserSDK, type BrowserSDKConfig, type WalletAddress } from '@thru/browser-sdk';
4
- import type { Thru } from '@thru/thru-sdk';
5
- import { ReactNode, useEffect, useState } from 'react';
3
+ import { BrowserSDK, type BrowserSDKConfig, type WalletAccount } from '@thru/browser-sdk';
4
+ import type { Thru } from '@thru/thru-sdk/client';
5
+ import { ReactNode, useCallback, useEffect, useState } from 'react';
6
6
  import { ThruContext } from './ThruContext';
7
7
 
8
8
  export interface ThruProviderProps {
@@ -18,18 +18,30 @@ export function ThruProvider({ children, config }: ThruProviderProps) {
18
18
  const [sdk, setSdk] = useState<BrowserSDK | null>(null);
19
19
  const [thru, setThru] = useState<Thru | null>(null);
20
20
  const [isConnected, setIsConnected] = useState(false);
21
- const [addresses, setAddresses] = useState<WalletAddress[]>([]);
21
+ const [accounts, setAccounts] = useState<WalletAccount[]>([]);
22
22
  const [isConnecting, setIsConnecting] = useState(false);
23
23
  const [error, setError] = useState<Error | null>(null);
24
+ const [selectedAccount, setSelectedAccount] = useState<WalletAccount | null>(null);
24
25
 
25
26
  useEffect(() => {
26
27
  // Create SDK instance
27
28
  const sdkInstance = new BrowserSDK(config);
28
29
  setSdk(sdkInstance);
29
-
30
30
  setThru(sdkInstance.getThru());
31
31
 
32
- // Initialize SDK (creates iframe)
32
+ const updateAccountsFromSdk = () => {
33
+ setAccounts(sdkInstance.getAccounts());
34
+ };
35
+
36
+ const updateSelectedAccount = (account?: WalletAccount | null) => {
37
+ if (account) {
38
+ setSelectedAccount(account);
39
+ return;
40
+ }
41
+ const fallback = sdkInstance.getSelectedAccount() ?? sdkInstance.getAccounts()[0] ?? null;
42
+ setSelectedAccount(fallback);
43
+ };
44
+
33
45
  sdkInstance.initialize().catch((err) => {
34
46
  console.error('Failed to initialize SDK:', err);
35
47
  setError(err);
@@ -43,16 +55,26 @@ export function ThruProvider({ children, config }: ThruProviderProps) {
43
55
  setError(null);
44
56
  } else {
45
57
  setIsConnected(true);
46
- setAddresses(sdkInstance.getAddresses());
58
+ updateAccountsFromSdk();
47
59
  setIsConnecting(false);
48
60
  setError(null);
61
+ if (result?.accounts?.length) {
62
+ setSelectedAccount(result.accounts[0]);
63
+ } else {
64
+ updateSelectedAccount();
65
+ }
49
66
  }
50
67
  };
51
68
 
52
- const handleDisconnect = () => {
69
+ const resetData = () => {
53
70
  setIsConnected(false);
54
- setAddresses([]);
71
+ setAccounts([]);
55
72
  setIsConnecting(false);
73
+ setSelectedAccount(null);
74
+ };
75
+
76
+ const handleDisconnect = () => {
77
+ resetData();
56
78
  };
57
79
 
58
80
  const handleError = (err: any) => {
@@ -61,15 +83,19 @@ export function ThruProvider({ children, config }: ThruProviderProps) {
61
83
  };
62
84
 
63
85
  const handleLock = () => {
64
- setIsConnected(false);
65
- setAddresses([]);
66
- setIsConnecting(false);
86
+ resetData();
87
+ };
88
+
89
+ const handleAccountChanged = (account: WalletAccount | null | undefined) => {
90
+ updateAccountsFromSdk();
91
+ updateSelectedAccount(account ?? undefined);
67
92
  };
68
93
 
69
94
  sdkInstance.on('connect', handleConnect);
70
95
  sdkInstance.on('disconnect', handleDisconnect);
71
96
  sdkInstance.on('error', handleError);
72
97
  sdkInstance.on('lock', handleLock);
98
+ sdkInstance.on('accountChanged', handleAccountChanged);
73
99
 
74
100
  // Cleanup on unmount
75
101
  return () => {
@@ -77,19 +103,45 @@ export function ThruProvider({ children, config }: ThruProviderProps) {
77
103
  sdkInstance.off('disconnect', handleDisconnect);
78
104
  sdkInstance.off('error', handleError);
79
105
  sdkInstance.off('lock', handleLock);
106
+ sdkInstance.off('accountChanged', handleAccountChanged);
80
107
  sdkInstance.destroy();
81
108
  };
82
109
  }, []); // Empty dependency array - only create SDK once
83
110
 
111
+ const selectAccount = useCallback(async (account: WalletAccount) => {
112
+ if (!sdk) {
113
+ throw new Error('BrowserSDK not initialized');
114
+ }
115
+
116
+ try {
117
+ const updated = await sdk.selectAccount(account.address);
118
+ setSelectedAccount(updated);
119
+ setAccounts(prev => {
120
+ const index = prev.findIndex(acc => acc.address === updated.address);
121
+ if (index >= 0) {
122
+ const next = [...prev];
123
+ next[index] = updated;
124
+ return next;
125
+ }
126
+ return [...prev, updated];
127
+ });
128
+ } catch (err) {
129
+ setError(err instanceof Error ? err : new Error('Failed to select account'));
130
+ throw err;
131
+ }
132
+ }, [sdk]);
133
+
84
134
  return (
85
135
  <ThruContext.Provider
86
136
  value={{
87
137
  thru,
88
138
  wallet: sdk,
89
139
  isConnected,
90
- addresses,
140
+ accounts,
91
141
  isConnecting,
92
142
  error,
143
+ selectedAccount,
144
+ selectAccount,
93
145
  }}
94
146
  >
95
147
  {children}
@@ -0,0 +1,38 @@
1
+ import type { WalletAccount } from '@thru/chain-interfaces';
2
+ import { useEffect, useMemo } from 'react';
3
+ import { useThru } from './useThru';
4
+
5
+ export interface UseAccountsResult {
6
+ accounts: WalletAccount[];
7
+ selectedAccount: WalletAccount | null;
8
+ isConnected: boolean;
9
+ isConnecting: boolean;
10
+ }
11
+
12
+ export interface UseAccountsOptions {
13
+ onAccountSelect?: (account: WalletAccount) => void;
14
+ }
15
+
16
+ /**
17
+ * useAccounts - Exposes connected wallet accounts and selection helpers.
18
+ */
19
+ export function useAccounts(options?: UseAccountsOptions): UseAccountsResult {
20
+ const { accounts, selectedAccount, isConnected, isConnecting } = useThru();
21
+ const externalOnSelect = options?.onAccountSelect;
22
+
23
+ useEffect(() => {
24
+ if (selectedAccount) {
25
+ externalOnSelect?.(selectedAccount);
26
+ }
27
+ }, [externalOnSelect, selectedAccount]);
28
+
29
+ return useMemo(
30
+ () => ({
31
+ accounts,
32
+ selectedAccount,
33
+ isConnected,
34
+ isConnecting,
35
+ }),
36
+ [accounts, selectedAccount, isConnected, isConnecting]
37
+ );
38
+ }
@@ -21,7 +21,7 @@ function waitForWallet(getWallet: () => BrowserSDK | null, timeout = 5000, inter
21
21
  * Returns the chain instance (if available) and a boolean indicating readiness.
22
22
  */
23
23
  export function useWallet() {
24
- const { wallet, isConnected, addresses } = useThru();
24
+ const { wallet, isConnected, accounts, selectedAccount, selectAccount, isConnecting } = useThru();
25
25
  const walletRef = useRef(wallet);
26
26
 
27
27
  useEffect(() => {
@@ -49,9 +49,12 @@ export function useWallet() {
49
49
 
50
50
  return {
51
51
  wallet: wallet?.thru as IThruChain | undefined,
52
- addresses,
52
+ accounts,
53
53
  connect,
54
54
  disconnect,
55
55
  isConnected: isConnected && !!wallet,
56
+ isConnecting,
57
+ selectedAccount,
58
+ selectAccount,
56
59
  };
57
60
  }
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export { ThruProvider, type ThruProviderProps } from './ThruProvider';
4
4
 
5
5
 
6
6
  // Hooks
7
+ export { useAccounts, type UseAccountsOptions, type UseAccountsResult } from './hooks/useAccounts';
7
8
  export { useThru } from './hooks/useThru';
8
9
  export { useWallet } from './hooks/useWallet';
9
10
 
@@ -13,5 +14,5 @@ export { BrowserSDK, ErrorCode, type BrowserSDKConfig, type ConnectOptions, type
13
14
  // Re-export types from chain-interfaces
14
15
  export type {
15
16
  ConnectResult, IThruChain, SignMessageParams,
16
- SignMessageResult, WalletAddress
17
+ SignMessageResult, WalletAccount
17
18
  } from '@thru/chain-interfaces';