@thru/react-sdk 0.0.4
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 +47 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
- package/src/ThruContext.ts +24 -0
- package/src/ThruProvider.tsx +98 -0
- package/src/hooks/useThru.ts +11 -0
- package/src/hooks/useWallet.ts +57 -0
- package/src/index.ts +17 -0
- package/tsconfig.json +10 -0
- package/tsup.config.ts +32 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BrowserSDK, BrowserSDKConfig, ConnectOptions } from '@thru/browser-sdk';
|
|
2
|
+
export { BrowserSDK, BrowserSDKConfig, ConnectOptions, ErrorCode, SDKEvent } from '@thru/browser-sdk';
|
|
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';
|
|
7
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
8
|
+
import { ReactNode } from 'react';
|
|
9
|
+
|
|
10
|
+
interface ThruContextValue {
|
|
11
|
+
wallet: BrowserSDK | null;
|
|
12
|
+
isConnected: boolean;
|
|
13
|
+
addresses: WalletAddress[];
|
|
14
|
+
isConnecting: boolean;
|
|
15
|
+
error: Error | null;
|
|
16
|
+
thru: Thru | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ThruProviderProps {
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
config: BrowserSDKConfig;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* ThruProvider - React context provider for Thru Wallet SDK
|
|
25
|
+
* Wraps the BrowserSDK and exposes state via context
|
|
26
|
+
*/
|
|
27
|
+
declare function ThruProvider({ children, config }: ThruProviderProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* useThru - Access the Thru SDK context
|
|
31
|
+
* Must be used within a ThruProvider
|
|
32
|
+
*/
|
|
33
|
+
declare function useThru(): ThruContextValue;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* useThruChain - Hook for accessing the Thru chain API exposed by the Browser SDK.
|
|
37
|
+
* Returns the chain instance (if available) and a boolean indicating readiness.
|
|
38
|
+
*/
|
|
39
|
+
declare function useWallet(): {
|
|
40
|
+
wallet: IThruChain | undefined;
|
|
41
|
+
addresses: _thru_chain_interfaces.WalletAddress[];
|
|
42
|
+
connect: (options?: ConnectOptions) => Promise<ConnectResult>;
|
|
43
|
+
disconnect: () => Promise<void>;
|
|
44
|
+
isConnected: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { type ThruContextValue, ThruProvider, type ThruProviderProps, useThru, useWallet };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { BrowserSDK } from '@thru/browser-sdk';
|
|
3
|
+
export { BrowserSDK, ErrorCode } from '@thru/browser-sdk';
|
|
4
|
+
import { createContext, useState, useEffect, useContext, useRef } from 'react';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var defaultContextValue = {
|
|
8
|
+
wallet: null,
|
|
9
|
+
isConnected: false,
|
|
10
|
+
addresses: [],
|
|
11
|
+
isConnecting: false,
|
|
12
|
+
error: null,
|
|
13
|
+
thru: null
|
|
14
|
+
};
|
|
15
|
+
var ThruContext = createContext(defaultContextValue);
|
|
16
|
+
function ThruProvider({ children, config }) {
|
|
17
|
+
const [sdk, setSdk] = useState(null);
|
|
18
|
+
const [thru, setThru] = useState(null);
|
|
19
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
20
|
+
const [addresses, setAddresses] = useState([]);
|
|
21
|
+
const [isConnecting, setIsConnecting] = useState(false);
|
|
22
|
+
const [error, setError] = useState(null);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const sdkInstance = new BrowserSDK(config);
|
|
25
|
+
setSdk(sdkInstance);
|
|
26
|
+
setThru(sdkInstance.getThru());
|
|
27
|
+
sdkInstance.initialize().catch((err) => {
|
|
28
|
+
console.error("Failed to initialize SDK:", err);
|
|
29
|
+
setError(err);
|
|
30
|
+
});
|
|
31
|
+
const handleConnect = (result) => {
|
|
32
|
+
if (result.status === "connecting") {
|
|
33
|
+
setIsConnecting(true);
|
|
34
|
+
setError(null);
|
|
35
|
+
} else {
|
|
36
|
+
setIsConnected(true);
|
|
37
|
+
setAddresses(sdkInstance.getAddresses());
|
|
38
|
+
setIsConnecting(false);
|
|
39
|
+
setError(null);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const handleDisconnect = () => {
|
|
43
|
+
setIsConnected(false);
|
|
44
|
+
setAddresses([]);
|
|
45
|
+
setIsConnecting(false);
|
|
46
|
+
};
|
|
47
|
+
const handleError = (err) => {
|
|
48
|
+
setError(err.error || new Error("Unknown error"));
|
|
49
|
+
setIsConnecting(false);
|
|
50
|
+
};
|
|
51
|
+
const handleLock = () => {
|
|
52
|
+
setIsConnected(false);
|
|
53
|
+
setAddresses([]);
|
|
54
|
+
setIsConnecting(false);
|
|
55
|
+
};
|
|
56
|
+
sdkInstance.on("connect", handleConnect);
|
|
57
|
+
sdkInstance.on("disconnect", handleDisconnect);
|
|
58
|
+
sdkInstance.on("error", handleError);
|
|
59
|
+
sdkInstance.on("lock", handleLock);
|
|
60
|
+
return () => {
|
|
61
|
+
sdkInstance.off("connect", handleConnect);
|
|
62
|
+
sdkInstance.off("disconnect", handleDisconnect);
|
|
63
|
+
sdkInstance.off("error", handleError);
|
|
64
|
+
sdkInstance.off("lock", handleLock);
|
|
65
|
+
sdkInstance.destroy();
|
|
66
|
+
};
|
|
67
|
+
}, []);
|
|
68
|
+
return /* @__PURE__ */ jsx(
|
|
69
|
+
ThruContext.Provider,
|
|
70
|
+
{
|
|
71
|
+
value: {
|
|
72
|
+
thru,
|
|
73
|
+
wallet: sdk,
|
|
74
|
+
isConnected,
|
|
75
|
+
addresses,
|
|
76
|
+
isConnecting,
|
|
77
|
+
error
|
|
78
|
+
},
|
|
79
|
+
children
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
function useThru() {
|
|
84
|
+
const context = useContext(ThruContext);
|
|
85
|
+
return context;
|
|
86
|
+
}
|
|
87
|
+
function waitForWallet(getWallet, timeout = 5e3, interval = 100) {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const start = Date.now();
|
|
90
|
+
const check = () => {
|
|
91
|
+
const sdk = getWallet();
|
|
92
|
+
if (sdk) return resolve(sdk);
|
|
93
|
+
if (Date.now() - start > timeout) return reject(new Error("SDK not initialized in time"));
|
|
94
|
+
setTimeout(check, interval);
|
|
95
|
+
};
|
|
96
|
+
check();
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function useWallet() {
|
|
100
|
+
const { wallet, isConnected, addresses } = useThru();
|
|
101
|
+
const walletRef = useRef(wallet);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
walletRef.current = wallet;
|
|
104
|
+
}, [wallet]);
|
|
105
|
+
const disconnect = async () => {
|
|
106
|
+
if (!wallet) {
|
|
107
|
+
throw new Error("SDK not initialized");
|
|
108
|
+
}
|
|
109
|
+
await wallet.disconnect();
|
|
110
|
+
};
|
|
111
|
+
const connect = async (options) => {
|
|
112
|
+
try {
|
|
113
|
+
const readySdk = walletRef.current ?? await waitForWallet(() => walletRef.current);
|
|
114
|
+
const result = await readySdk.connect(options);
|
|
115
|
+
return result;
|
|
116
|
+
} catch (err) {
|
|
117
|
+
const error = err;
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
wallet: wallet?.thru,
|
|
123
|
+
addresses,
|
|
124
|
+
connect,
|
|
125
|
+
disconnect,
|
|
126
|
+
isConnected: isConnected && !!wallet
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { ThruProvider, useThru, useWallet };
|
|
131
|
+
//# sourceMappingURL=index.js.map
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ThruContext.ts","../src/ThruProvider.tsx","../src/hooks/useThru.ts","../src/hooks/useWallet.ts"],"names":["useEffect"],"mappings":"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","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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thru/react-sdk",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@thru/browser-sdk": "0.0.4",
|
|
15
|
+
"@thru/chain-interfaces": "0.0.4",
|
|
16
|
+
"@thru/thru-sdk": "0.0.4"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
20
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/react": "^19.0.0",
|
|
24
|
+
"@types/react-dom": "^19.0.0"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"lint": "eslint src/",
|
|
30
|
+
"clean": "rm -rf dist"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BrowserSDK } from "@thru/browser-sdk";
|
|
2
|
+
import { WalletAddress } from "@thru/chain-interfaces";
|
|
3
|
+
import { Thru } from "@thru/thru-sdk";
|
|
4
|
+
import { createContext } from "react";
|
|
5
|
+
|
|
6
|
+
export interface ThruContextValue {
|
|
7
|
+
wallet: BrowserSDK | null;
|
|
8
|
+
isConnected: boolean;
|
|
9
|
+
addresses: WalletAddress[];
|
|
10
|
+
isConnecting: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
thru: Thru | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const defaultContextValue: ThruContextValue = {
|
|
16
|
+
wallet: null,
|
|
17
|
+
isConnected: false,
|
|
18
|
+
addresses: [],
|
|
19
|
+
isConnecting: false,
|
|
20
|
+
error: null,
|
|
21
|
+
thru: null,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const ThruContext = createContext<ThruContextValue>(defaultContextValue);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use client';
|
|
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';
|
|
6
|
+
import { ThruContext } from './ThruContext';
|
|
7
|
+
|
|
8
|
+
export interface ThruProviderProps {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
config: BrowserSDKConfig;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ThruProvider - React context provider for Thru Wallet SDK
|
|
15
|
+
* Wraps the BrowserSDK and exposes state via context
|
|
16
|
+
*/
|
|
17
|
+
export function ThruProvider({ children, config }: ThruProviderProps) {
|
|
18
|
+
const [sdk, setSdk] = useState<BrowserSDK | null>(null);
|
|
19
|
+
const [thru, setThru] = useState<Thru | null>(null);
|
|
20
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
21
|
+
const [addresses, setAddresses] = useState<WalletAddress[]>([]);
|
|
22
|
+
const [isConnecting, setIsConnecting] = useState(false);
|
|
23
|
+
const [error, setError] = useState<Error | null>(null);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
// Create SDK instance
|
|
27
|
+
const sdkInstance = new BrowserSDK(config);
|
|
28
|
+
setSdk(sdkInstance);
|
|
29
|
+
|
|
30
|
+
setThru(sdkInstance.getThru());
|
|
31
|
+
|
|
32
|
+
// Initialize SDK (creates iframe)
|
|
33
|
+
sdkInstance.initialize().catch((err) => {
|
|
34
|
+
console.error('Failed to initialize SDK:', err);
|
|
35
|
+
setError(err);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Listen to SDK events
|
|
39
|
+
const handleConnect = (result: any) => {
|
|
40
|
+
// Check if this is the initial "connecting" status or actual connection
|
|
41
|
+
if (result.status === 'connecting') {
|
|
42
|
+
setIsConnecting(true);
|
|
43
|
+
setError(null);
|
|
44
|
+
} else {
|
|
45
|
+
setIsConnected(true);
|
|
46
|
+
setAddresses(sdkInstance.getAddresses());
|
|
47
|
+
setIsConnecting(false);
|
|
48
|
+
setError(null);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleDisconnect = () => {
|
|
53
|
+
setIsConnected(false);
|
|
54
|
+
setAddresses([]);
|
|
55
|
+
setIsConnecting(false);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleError = (err: any) => {
|
|
59
|
+
setError(err.error || new Error('Unknown error'));
|
|
60
|
+
setIsConnecting(false);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const handleLock = () => {
|
|
64
|
+
setIsConnected(false);
|
|
65
|
+
setAddresses([]);
|
|
66
|
+
setIsConnecting(false);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
sdkInstance.on('connect', handleConnect);
|
|
70
|
+
sdkInstance.on('disconnect', handleDisconnect);
|
|
71
|
+
sdkInstance.on('error', handleError);
|
|
72
|
+
sdkInstance.on('lock', handleLock);
|
|
73
|
+
|
|
74
|
+
// Cleanup on unmount
|
|
75
|
+
return () => {
|
|
76
|
+
sdkInstance.off('connect', handleConnect);
|
|
77
|
+
sdkInstance.off('disconnect', handleDisconnect);
|
|
78
|
+
sdkInstance.off('error', handleError);
|
|
79
|
+
sdkInstance.off('lock', handleLock);
|
|
80
|
+
sdkInstance.destroy();
|
|
81
|
+
};
|
|
82
|
+
}, []); // Empty dependency array - only create SDK once
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<ThruContext.Provider
|
|
86
|
+
value={{
|
|
87
|
+
thru,
|
|
88
|
+
wallet: sdk,
|
|
89
|
+
isConnected,
|
|
90
|
+
addresses,
|
|
91
|
+
isConnecting,
|
|
92
|
+
error,
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{children}
|
|
96
|
+
</ThruContext.Provider>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { ThruContext } from "../ThruContext";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* useThru - Access the Thru SDK context
|
|
6
|
+
* Must be used within a ThruProvider
|
|
7
|
+
*/
|
|
8
|
+
export function useThru() {
|
|
9
|
+
const context = useContext(ThruContext);
|
|
10
|
+
return context;
|
|
11
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BrowserSDK, ConnectOptions } from '@thru/browser-sdk';
|
|
2
|
+
import type { ConnectResult, IThruChain } from '@thru/chain-interfaces';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import { useThru } from './useThru';
|
|
5
|
+
|
|
6
|
+
function waitForWallet(getWallet: () => BrowserSDK | null, timeout = 5000, interval = 100): Promise<BrowserSDK> {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const start = Date.now();
|
|
9
|
+
const check = () => {
|
|
10
|
+
const sdk = getWallet();
|
|
11
|
+
if (sdk) return resolve(sdk);
|
|
12
|
+
if (Date.now() - start > timeout) return reject(new Error('SDK not initialized in time'));
|
|
13
|
+
setTimeout(check, interval);
|
|
14
|
+
};
|
|
15
|
+
check();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* useThruChain - Hook for accessing the Thru chain API exposed by the Browser SDK.
|
|
21
|
+
* Returns the chain instance (if available) and a boolean indicating readiness.
|
|
22
|
+
*/
|
|
23
|
+
export function useWallet() {
|
|
24
|
+
const { wallet, isConnected, addresses } = useThru();
|
|
25
|
+
const walletRef = useRef(wallet);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
walletRef.current = wallet;
|
|
29
|
+
}, [wallet]);
|
|
30
|
+
|
|
31
|
+
const disconnect = async (): Promise<void> => {
|
|
32
|
+
if (!wallet) {
|
|
33
|
+
throw new Error('SDK not initialized');
|
|
34
|
+
}
|
|
35
|
+
await wallet.disconnect();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const connect = async (options?: ConnectOptions): Promise<ConnectResult> => {
|
|
39
|
+
try {
|
|
40
|
+
const readySdk =
|
|
41
|
+
walletRef.current ?? (await waitForWallet(() => walletRef.current));
|
|
42
|
+
const result = await readySdk.connect(options);
|
|
43
|
+
return result;
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const error = err as Error;
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
wallet: wallet?.thru as IThruChain | undefined,
|
|
52
|
+
addresses,
|
|
53
|
+
connect,
|
|
54
|
+
disconnect,
|
|
55
|
+
isConnected: isConnected && !!wallet,
|
|
56
|
+
};
|
|
57
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Provider and context
|
|
2
|
+
export type { ThruContextValue } from './ThruContext';
|
|
3
|
+
export { ThruProvider, type ThruProviderProps } from './ThruProvider';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
// Hooks
|
|
7
|
+
export { useThru } from './hooks/useThru';
|
|
8
|
+
export { useWallet } from './hooks/useWallet';
|
|
9
|
+
|
|
10
|
+
// Re-export from browser-sdk for convenience
|
|
11
|
+
export { BrowserSDK, ErrorCode, type BrowserSDKConfig, type ConnectOptions, type SDKEvent } from '@thru/browser-sdk';
|
|
12
|
+
|
|
13
|
+
// Re-export types from chain-interfaces
|
|
14
|
+
export type {
|
|
15
|
+
ConnectResult, IThruChain, SignMessageParams,
|
|
16
|
+
SignMessageResult, WalletAddress
|
|
17
|
+
} from '@thru/chain-interfaces';
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
entry: ['src/index.ts'],
|
|
8
|
+
format: ['esm'],
|
|
9
|
+
dts: true,
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
clean: true,
|
|
12
|
+
treeshake: true,
|
|
13
|
+
platform: 'browser',
|
|
14
|
+
banner: {
|
|
15
|
+
js: '"use client";',
|
|
16
|
+
},
|
|
17
|
+
noExternal: ['@thru/chain-interfaces'],
|
|
18
|
+
external: [
|
|
19
|
+
'@thru/browser-sdk',
|
|
20
|
+
'@thru/embedded-provider',
|
|
21
|
+
'react',
|
|
22
|
+
'react-dom',
|
|
23
|
+
],
|
|
24
|
+
onSuccess: () => {
|
|
25
|
+
const distDir = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const outputPath = join(distDir, 'dist', 'index.js');
|
|
27
|
+
const content = readFileSync(outputPath, 'utf8');
|
|
28
|
+
if (!content.startsWith('"use client";')) {
|
|
29
|
+
writeFileSync(outputPath, `"use client";\n${content}`);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
});
|