@thru/browser-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 +85 -0
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -0
- package/package.json +25 -0
- package/src/BrowserSDK.ts +264 -0
- package/src/index.ts +20 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +23 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { AddressType, ConnectResult, WalletAddress, IThruChain } from '@thru/chain-interfaces';
|
|
2
|
+
export { ConnectResult, IThruChain, SignMessageParams, SignMessageResult, WalletAddress } from '@thru/chain-interfaces';
|
|
3
|
+
import { ConnectMetadataInput } from '@thru/protocol';
|
|
4
|
+
import { Thru } from '@thru/thru-sdk';
|
|
5
|
+
export { ErrorCode } from '@thru/embedded-provider';
|
|
6
|
+
|
|
7
|
+
interface BrowserSDKConfig {
|
|
8
|
+
iframeUrl?: string;
|
|
9
|
+
addressTypes?: AddressType[];
|
|
10
|
+
rpcUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
interface ConnectOptions {
|
|
13
|
+
metadata?: ConnectMetadataInput;
|
|
14
|
+
}
|
|
15
|
+
type SDKEvent = 'connect' | 'disconnect' | 'lock' | 'error';
|
|
16
|
+
type EventCallback = (...args: any[]) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Browser SDK - Main entry point for dApp developers
|
|
19
|
+
* Wraps EmbeddedProvider with a clean, simple API
|
|
20
|
+
*/
|
|
21
|
+
declare class BrowserSDK {
|
|
22
|
+
private provider;
|
|
23
|
+
private eventListeners;
|
|
24
|
+
private initialized;
|
|
25
|
+
private thruClient;
|
|
26
|
+
private connectInFlight;
|
|
27
|
+
private lastConnectResult;
|
|
28
|
+
constructor(config?: BrowserSDKConfig);
|
|
29
|
+
/**
|
|
30
|
+
* Initialize the SDK (creates iframe)
|
|
31
|
+
* Must be called before using the SDK
|
|
32
|
+
*/
|
|
33
|
+
initialize(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Connect to wallet
|
|
36
|
+
* Shows wallet modal and requests connection
|
|
37
|
+
*/
|
|
38
|
+
connect(options?: ConnectOptions): Promise<ConnectResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Disconnect from wallet
|
|
41
|
+
*/
|
|
42
|
+
disconnect(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if connected
|
|
45
|
+
*/
|
|
46
|
+
isConnected(): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Get all addresses
|
|
49
|
+
*/
|
|
50
|
+
getAddresses(): WalletAddress[];
|
|
51
|
+
/**
|
|
52
|
+
* Get Thru chain API (iframe-backed signer)
|
|
53
|
+
*/
|
|
54
|
+
get thru(): IThruChain;
|
|
55
|
+
/**
|
|
56
|
+
* Event emitter: on
|
|
57
|
+
*/
|
|
58
|
+
on(event: SDKEvent, callback: EventCallback): void;
|
|
59
|
+
/**
|
|
60
|
+
* Event emitter: off
|
|
61
|
+
*/
|
|
62
|
+
off(event: SDKEvent, callback: EventCallback): void;
|
|
63
|
+
/**
|
|
64
|
+
* Event emitter: once (listen once and auto-remove)
|
|
65
|
+
*/
|
|
66
|
+
once(event: SDKEvent, callback: EventCallback): void;
|
|
67
|
+
/**
|
|
68
|
+
* Emit event to all listeners
|
|
69
|
+
*/
|
|
70
|
+
private emit;
|
|
71
|
+
/**
|
|
72
|
+
* Set up event forwarding from provider to SDK
|
|
73
|
+
*/
|
|
74
|
+
private setupEventForwarding;
|
|
75
|
+
/**
|
|
76
|
+
* Destroy SDK and cleanup
|
|
77
|
+
*/
|
|
78
|
+
destroy(): void;
|
|
79
|
+
private resolveMetadata;
|
|
80
|
+
private resolveAppUrl;
|
|
81
|
+
private deriveAppName;
|
|
82
|
+
getThru(): Thru;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { BrowserSDK, type BrowserSDKConfig, type ConnectOptions, type EventCallback, type SDKEvent };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { EmbeddedProvider } from '@thru/embedded-provider';
|
|
2
|
+
export { ErrorCode } from '@thru/embedded-provider';
|
|
3
|
+
import { EMBEDDED_PROVIDER_EVENTS } from '@thru/protocol';
|
|
4
|
+
import { createThruClient } from '@thru/thru-sdk';
|
|
5
|
+
|
|
6
|
+
// ../chain-interfaces/dist/index.js
|
|
7
|
+
var AddressType = {
|
|
8
|
+
THRU: "thru"
|
|
9
|
+
};
|
|
10
|
+
var BrowserSDK = class {
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
this.eventListeners = /* @__PURE__ */ new Map();
|
|
13
|
+
this.initialized = false;
|
|
14
|
+
this.connectInFlight = null;
|
|
15
|
+
this.lastConnectResult = null;
|
|
16
|
+
this.provider = new EmbeddedProvider({
|
|
17
|
+
iframeUrl: config.iframeUrl,
|
|
18
|
+
addressTypes: config.addressTypes || [AddressType.THRU]
|
|
19
|
+
});
|
|
20
|
+
this.thruClient = createThruClient({
|
|
21
|
+
baseUrl: config.rpcUrl
|
|
22
|
+
});
|
|
23
|
+
this.setupEventForwarding();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the SDK (creates iframe)
|
|
27
|
+
* Must be called before using the SDK
|
|
28
|
+
*/
|
|
29
|
+
async initialize() {
|
|
30
|
+
if (this.initialized) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
await this.provider.initialize();
|
|
34
|
+
this.initialized = true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Connect to wallet
|
|
38
|
+
* Shows wallet modal and requests connection
|
|
39
|
+
*/
|
|
40
|
+
async connect(options) {
|
|
41
|
+
if (!this.initialized) {
|
|
42
|
+
await this.initialize();
|
|
43
|
+
}
|
|
44
|
+
if (this.connectInFlight) {
|
|
45
|
+
return this.connectInFlight;
|
|
46
|
+
}
|
|
47
|
+
if (this.lastConnectResult && this.provider.isConnected()) {
|
|
48
|
+
return this.lastConnectResult;
|
|
49
|
+
}
|
|
50
|
+
this.emit("connect", { status: "connecting" });
|
|
51
|
+
const inFlight = (async () => {
|
|
52
|
+
try {
|
|
53
|
+
const metadata = this.resolveMetadata(options?.metadata);
|
|
54
|
+
const providerOptions = metadata ? { metadata } : void 0;
|
|
55
|
+
const result = await this.provider.connect(providerOptions);
|
|
56
|
+
this.lastConnectResult = result;
|
|
57
|
+
this.emit("connect", result);
|
|
58
|
+
return result;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
this.emit("error", error);
|
|
61
|
+
throw error;
|
|
62
|
+
} finally {
|
|
63
|
+
this.connectInFlight = null;
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
66
|
+
this.connectInFlight = inFlight;
|
|
67
|
+
return inFlight;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Disconnect from wallet
|
|
71
|
+
*/
|
|
72
|
+
async disconnect() {
|
|
73
|
+
try {
|
|
74
|
+
await this.provider.disconnect();
|
|
75
|
+
this.emit("disconnect", {});
|
|
76
|
+
this.lastConnectResult = null;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
this.emit("error", error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if connected
|
|
84
|
+
*/
|
|
85
|
+
isConnected() {
|
|
86
|
+
return this.provider.isConnected();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get all addresses
|
|
90
|
+
*/
|
|
91
|
+
getAddresses() {
|
|
92
|
+
return this.provider.getAddresses();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get Thru chain API (iframe-backed signer)
|
|
96
|
+
*/
|
|
97
|
+
get thru() {
|
|
98
|
+
return this.provider.thru;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Event emitter: on
|
|
102
|
+
*/
|
|
103
|
+
on(event, callback) {
|
|
104
|
+
if (!this.eventListeners.has(event)) {
|
|
105
|
+
this.eventListeners.set(event, /* @__PURE__ */ new Set());
|
|
106
|
+
}
|
|
107
|
+
this.eventListeners.get(event).add(callback);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Event emitter: off
|
|
111
|
+
*/
|
|
112
|
+
off(event, callback) {
|
|
113
|
+
this.eventListeners.get(event)?.delete(callback);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Event emitter: once (listen once and auto-remove)
|
|
117
|
+
*/
|
|
118
|
+
once(event, callback) {
|
|
119
|
+
const wrappedCallback = (...args) => {
|
|
120
|
+
callback(...args);
|
|
121
|
+
this.off(event, wrappedCallback);
|
|
122
|
+
};
|
|
123
|
+
this.on(event, wrappedCallback);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Emit event to all listeners
|
|
127
|
+
*/
|
|
128
|
+
emit(event, data) {
|
|
129
|
+
this.eventListeners.get(event)?.forEach((callback) => {
|
|
130
|
+
try {
|
|
131
|
+
callback(data);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error(`Error in SDK event listener for ${event}:`, error);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Set up event forwarding from provider to SDK
|
|
139
|
+
*/
|
|
140
|
+
setupEventForwarding() {
|
|
141
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.CONNECT, (data) => {
|
|
142
|
+
});
|
|
143
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.DISCONNECT, (data) => {
|
|
144
|
+
this.emit("disconnect", data);
|
|
145
|
+
});
|
|
146
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.ERROR, (data) => {
|
|
147
|
+
this.emit("error", data);
|
|
148
|
+
});
|
|
149
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.LOCK, (data) => {
|
|
150
|
+
this.emit("lock", data);
|
|
151
|
+
this.emit("disconnect", { reason: "locked" });
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Destroy SDK and cleanup
|
|
156
|
+
*/
|
|
157
|
+
destroy() {
|
|
158
|
+
this.provider.destroy();
|
|
159
|
+
this.eventListeners.clear();
|
|
160
|
+
this.initialized = false;
|
|
161
|
+
this.connectInFlight = null;
|
|
162
|
+
this.lastConnectResult = null;
|
|
163
|
+
}
|
|
164
|
+
resolveMetadata(input) {
|
|
165
|
+
const defaultOrigin = typeof window !== "undefined" ? window.location.origin : void 0;
|
|
166
|
+
if (!defaultOrigin && !input) {
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
const appId = input?.appId || defaultOrigin;
|
|
170
|
+
const appUrl = this.resolveAppUrl(defaultOrigin, input?.appUrl);
|
|
171
|
+
const appName = input?.appName || this.deriveAppName(appUrl ?? appId);
|
|
172
|
+
const metadata = {};
|
|
173
|
+
if (appId) metadata.appId = appId;
|
|
174
|
+
if (appUrl) metadata.appUrl = appUrl;
|
|
175
|
+
if (appName) metadata.appName = appName;
|
|
176
|
+
if (input?.imageUrl) metadata.imageUrl = input.imageUrl;
|
|
177
|
+
return metadata;
|
|
178
|
+
}
|
|
179
|
+
resolveAppUrl(defaultOrigin, providedUrl) {
|
|
180
|
+
const candidate = providedUrl || defaultOrigin;
|
|
181
|
+
if (!candidate) {
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const url = new URL(candidate, defaultOrigin);
|
|
186
|
+
return url.toString();
|
|
187
|
+
} catch {
|
|
188
|
+
return defaultOrigin;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
deriveAppName(source) {
|
|
192
|
+
if (!source) {
|
|
193
|
+
return void 0;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const hostname = new URL(source).hostname;
|
|
197
|
+
return hostname || source;
|
|
198
|
+
} catch {
|
|
199
|
+
return source;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
getThru() {
|
|
203
|
+
return this.thruClient;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export { BrowserSDK };
|
|
208
|
+
//# sourceMappingURL=index.js.map
|
|
209
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../chain-interfaces/src/types.ts","../src/BrowserSDK.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const AddressType = {\n THRU: 'thru',\n} as const;\n\nexport type AddressType = typeof AddressType[keyof typeof AddressType];\n\nexport interface WalletAddress {\n addressType: AddressType;\n address: string;\n}\n\nexport interface AppMetadata {\n appId: string;\n appName: string;\n appUrl: string;\n imageUrl?: string;\n}\n\nexport interface ConnectResult {\n walletId?: string;\n addresses: WalletAddress[];\n status?: 'pending' | 'completed';\n metadata?: AppMetadata;\n}\n\nexport interface ConnectedApp {\n accountId: number;\n appId: string;\n origin: string;\n metadata: AppMetadata;\n connectedAt: number;\n updatedAt: number;\n}\n\nexport interface SignMessageParams {\n message: string | Uint8Array;\n networkId: string;\n}\n\nexport interface SignMessageResult {\n signature: Uint8Array;\n publicKey: string;\n}\n","import type {\n AddressType as AddressTypeValue,\n ConnectResult,\n IThruChain,\n WalletAddress,\n} from '@thru/chain-interfaces';\nimport { AddressType } from '@thru/chain-interfaces';\nimport { EmbeddedProvider } from '@thru/embedded-provider';\nimport { EMBEDDED_PROVIDER_EVENTS, type ConnectMetadataInput } from '@thru/protocol';\nimport { createThruClient, Thru } from '@thru/thru-sdk';\n\nexport interface BrowserSDKConfig {\n iframeUrl?: string;\n addressTypes?: AddressTypeValue[];\n rpcUrl?: string;\n}\n\nexport interface ConnectOptions {\n metadata?: ConnectMetadataInput;\n}\n\nexport type SDKEvent = 'connect' | 'disconnect' | 'lock' | 'error';\n\nexport type EventCallback = (...args: any[]) => void;\n\n/**\n * Browser SDK - Main entry point for dApp developers\n * Wraps EmbeddedProvider with a clean, simple API\n */\nexport class BrowserSDK {\n private provider: EmbeddedProvider;\n private eventListeners = new Map<SDKEvent, Set<EventCallback>>();\n private initialized = false;\n private thruClient: Thru;\n private connectInFlight: Promise<ConnectResult> | null = null;\n private lastConnectResult: ConnectResult | null = null;\n\n constructor(config: BrowserSDKConfig = {}) {\n this.provider = new EmbeddedProvider({\n iframeUrl: config.iframeUrl,\n addressTypes: config.addressTypes || [AddressType.THRU],\n });\n\n this.thruClient = createThruClient({\n baseUrl: config.rpcUrl,\n });\n\n // Forward provider events to SDK events\n this.setupEventForwarding();\n }\n\n /**\n * Initialize the SDK (creates iframe)\n * Must be called before using the SDK\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n await this.provider.initialize();\n this.initialized = true;\n }\n\n /**\n * Connect to wallet\n * Shows wallet modal and requests connection\n */\n async connect(options?: ConnectOptions): Promise<ConnectResult> {\n // Auto-initialize if not done yet\n if (!this.initialized) {\n await this.initialize();\n }\n\n if (this.connectInFlight) {\n return this.connectInFlight;\n }\n\n if (this.lastConnectResult && this.provider.isConnected()) {\n return this.lastConnectResult;\n }\n\n this.emit('connect', { status: 'connecting' });\n\n const inFlight = (async () => {\n try {\n const metadata = this.resolveMetadata(options?.metadata);\n const providerOptions = metadata ? { metadata } : undefined;\n const result = await this.provider.connect(providerOptions);\n this.lastConnectResult = result;\n this.emit('connect', result);\n return result;\n } catch (error) {\n this.emit('error', error);\n throw error;\n } finally {\n this.connectInFlight = null;\n }\n })();\n\n this.connectInFlight = inFlight;\n return inFlight;\n }\n\n /**\n * Disconnect from wallet\n */\n async disconnect(): Promise<void> {\n try {\n await this.provider.disconnect();\n this.emit('disconnect', {});\n this.lastConnectResult = null;\n } catch (error) {\n this.emit('error', error);\n throw error;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.provider.isConnected();\n }\n\n /**\n * Get all addresses\n */\n getAddresses(): WalletAddress[] {\n return this.provider.getAddresses();\n }\n\n /**\n * Get Thru chain API (iframe-backed signer)\n */\n get thru(): IThruChain {\n return this.provider.thru;\n }\n\n /**\n * Event emitter: on\n */\n on(event: SDKEvent, callback: EventCallback): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(callback);\n }\n\n /**\n * Event emitter: off\n */\n off(event: SDKEvent, callback: EventCallback): void {\n this.eventListeners.get(event)?.delete(callback);\n }\n\n /**\n * Event emitter: once (listen once and auto-remove)\n */\n once(event: SDKEvent, callback: EventCallback): void {\n const wrappedCallback = (...args: any[]) => {\n callback(...args);\n this.off(event, wrappedCallback);\n };\n this.on(event, wrappedCallback);\n }\n\n /**\n * Emit event to all listeners\n */\n private emit(event: SDKEvent, data?: any): void {\n this.eventListeners.get(event)?.forEach(callback => {\n try {\n callback(data);\n } catch (error) {\n console.error(`Error in SDK event listener for ${event}:`, error);\n }\n });\n }\n\n /**\n * Set up event forwarding from provider to SDK\n */\n private setupEventForwarding(): void {\n // Forward all relevant provider events to SDK events\n this.provider.on(EMBEDDED_PROVIDER_EVENTS.CONNECT, (data: any) => {\n // Already handled in connect() method\n });\n\n this.provider.on(EMBEDDED_PROVIDER_EVENTS.DISCONNECT, (data: any) => {\n this.emit('disconnect', data);\n });\n\n this.provider.on(EMBEDDED_PROVIDER_EVENTS.ERROR, (data: any) => {\n this.emit('error', data);\n });\n\n this.provider.on(EMBEDDED_PROVIDER_EVENTS.LOCK, (data: any) => {\n this.emit('lock', data);\n this.emit('disconnect', { reason: 'locked' });\n });\n }\n\n /**\n * Destroy SDK and cleanup\n */\n destroy(): void {\n this.provider.destroy();\n this.eventListeners.clear();\n this.initialized = false;\n this.connectInFlight = null;\n this.lastConnectResult = null;\n }\n\n private resolveMetadata(input?: ConnectMetadataInput): ConnectMetadataInput | undefined {\n const defaultOrigin = typeof window !== 'undefined' ? window.location.origin : undefined;\n if (!defaultOrigin && !input) {\n return undefined;\n }\n\n const appId = input?.appId || defaultOrigin;\n const appUrl = this.resolveAppUrl(defaultOrigin, input?.appUrl);\n const appName = input?.appName || this.deriveAppName(appUrl ?? appId);\n\n const metadata: ConnectMetadataInput = {};\n if (appId) metadata.appId = appId;\n if (appUrl) metadata.appUrl = appUrl;\n if (appName) metadata.appName = appName;\n if (input?.imageUrl) metadata.imageUrl = input.imageUrl;\n\n return metadata;\n }\n\n private resolveAppUrl(defaultOrigin?: string, providedUrl?: string): string | undefined {\n const candidate = providedUrl || defaultOrigin;\n if (!candidate) {\n return undefined;\n }\n\n try {\n const url = new URL(candidate, defaultOrigin);\n return url.toString();\n } catch {\n return defaultOrigin;\n }\n }\n\n private deriveAppName(source?: string): string | undefined {\n if (!source) {\n return undefined;\n }\n\n try {\n const hostname = new URL(source).hostname;\n return hostname || source;\n } catch {\n return source;\n }\n }\n\n public getThru(): Thru {\n return this.thruClient;\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thru/browser-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/embedded-provider": "0.0.4",
|
|
15
|
+
"@thru/chain-interfaces": "0.0.4",
|
|
16
|
+
"@thru/protocol": "0.0.4",
|
|
17
|
+
"@thru/thru-sdk": "0.0.4"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"lint": "eslint src/",
|
|
23
|
+
"clean": "rm -rf dist"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AddressType as AddressTypeValue,
|
|
3
|
+
ConnectResult,
|
|
4
|
+
IThruChain,
|
|
5
|
+
WalletAddress,
|
|
6
|
+
} from '@thru/chain-interfaces';
|
|
7
|
+
import { AddressType } from '@thru/chain-interfaces';
|
|
8
|
+
import { EmbeddedProvider } from '@thru/embedded-provider';
|
|
9
|
+
import { EMBEDDED_PROVIDER_EVENTS, type ConnectMetadataInput } from '@thru/protocol';
|
|
10
|
+
import { createThruClient, Thru } from '@thru/thru-sdk';
|
|
11
|
+
|
|
12
|
+
export interface BrowserSDKConfig {
|
|
13
|
+
iframeUrl?: string;
|
|
14
|
+
addressTypes?: AddressTypeValue[];
|
|
15
|
+
rpcUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ConnectOptions {
|
|
19
|
+
metadata?: ConnectMetadataInput;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SDKEvent = 'connect' | 'disconnect' | 'lock' | 'error';
|
|
23
|
+
|
|
24
|
+
export type EventCallback = (...args: any[]) => void;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Browser SDK - Main entry point for dApp developers
|
|
28
|
+
* Wraps EmbeddedProvider with a clean, simple API
|
|
29
|
+
*/
|
|
30
|
+
export class BrowserSDK {
|
|
31
|
+
private provider: EmbeddedProvider;
|
|
32
|
+
private eventListeners = new Map<SDKEvent, Set<EventCallback>>();
|
|
33
|
+
private initialized = false;
|
|
34
|
+
private thruClient: Thru;
|
|
35
|
+
private connectInFlight: Promise<ConnectResult> | null = null;
|
|
36
|
+
private lastConnectResult: ConnectResult | null = null;
|
|
37
|
+
|
|
38
|
+
constructor(config: BrowserSDKConfig = {}) {
|
|
39
|
+
this.provider = new EmbeddedProvider({
|
|
40
|
+
iframeUrl: config.iframeUrl,
|
|
41
|
+
addressTypes: config.addressTypes || [AddressType.THRU],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this.thruClient = createThruClient({
|
|
45
|
+
baseUrl: config.rpcUrl,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Forward provider events to SDK events
|
|
49
|
+
this.setupEventForwarding();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Initialize the SDK (creates iframe)
|
|
54
|
+
* Must be called before using the SDK
|
|
55
|
+
*/
|
|
56
|
+
async initialize(): Promise<void> {
|
|
57
|
+
if (this.initialized) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await this.provider.initialize();
|
|
62
|
+
this.initialized = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Connect to wallet
|
|
67
|
+
* Shows wallet modal and requests connection
|
|
68
|
+
*/
|
|
69
|
+
async connect(options?: ConnectOptions): Promise<ConnectResult> {
|
|
70
|
+
// Auto-initialize if not done yet
|
|
71
|
+
if (!this.initialized) {
|
|
72
|
+
await this.initialize();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.connectInFlight) {
|
|
76
|
+
return this.connectInFlight;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (this.lastConnectResult && this.provider.isConnected()) {
|
|
80
|
+
return this.lastConnectResult;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.emit('connect', { status: 'connecting' });
|
|
84
|
+
|
|
85
|
+
const inFlight = (async () => {
|
|
86
|
+
try {
|
|
87
|
+
const metadata = this.resolveMetadata(options?.metadata);
|
|
88
|
+
const providerOptions = metadata ? { metadata } : undefined;
|
|
89
|
+
const result = await this.provider.connect(providerOptions);
|
|
90
|
+
this.lastConnectResult = result;
|
|
91
|
+
this.emit('connect', result);
|
|
92
|
+
return result;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
this.emit('error', error);
|
|
95
|
+
throw error;
|
|
96
|
+
} finally {
|
|
97
|
+
this.connectInFlight = null;
|
|
98
|
+
}
|
|
99
|
+
})();
|
|
100
|
+
|
|
101
|
+
this.connectInFlight = inFlight;
|
|
102
|
+
return inFlight;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Disconnect from wallet
|
|
107
|
+
*/
|
|
108
|
+
async disconnect(): Promise<void> {
|
|
109
|
+
try {
|
|
110
|
+
await this.provider.disconnect();
|
|
111
|
+
this.emit('disconnect', {});
|
|
112
|
+
this.lastConnectResult = null;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
this.emit('error', error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Check if connected
|
|
121
|
+
*/
|
|
122
|
+
isConnected(): boolean {
|
|
123
|
+
return this.provider.isConnected();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get all addresses
|
|
128
|
+
*/
|
|
129
|
+
getAddresses(): WalletAddress[] {
|
|
130
|
+
return this.provider.getAddresses();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get Thru chain API (iframe-backed signer)
|
|
135
|
+
*/
|
|
136
|
+
get thru(): IThruChain {
|
|
137
|
+
return this.provider.thru;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Event emitter: on
|
|
142
|
+
*/
|
|
143
|
+
on(event: SDKEvent, callback: EventCallback): void {
|
|
144
|
+
if (!this.eventListeners.has(event)) {
|
|
145
|
+
this.eventListeners.set(event, new Set());
|
|
146
|
+
}
|
|
147
|
+
this.eventListeners.get(event)!.add(callback);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Event emitter: off
|
|
152
|
+
*/
|
|
153
|
+
off(event: SDKEvent, callback: EventCallback): void {
|
|
154
|
+
this.eventListeners.get(event)?.delete(callback);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Event emitter: once (listen once and auto-remove)
|
|
159
|
+
*/
|
|
160
|
+
once(event: SDKEvent, callback: EventCallback): void {
|
|
161
|
+
const wrappedCallback = (...args: any[]) => {
|
|
162
|
+
callback(...args);
|
|
163
|
+
this.off(event, wrappedCallback);
|
|
164
|
+
};
|
|
165
|
+
this.on(event, wrappedCallback);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Emit event to all listeners
|
|
170
|
+
*/
|
|
171
|
+
private emit(event: SDKEvent, data?: any): void {
|
|
172
|
+
this.eventListeners.get(event)?.forEach(callback => {
|
|
173
|
+
try {
|
|
174
|
+
callback(data);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(`Error in SDK event listener for ${event}:`, error);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Set up event forwarding from provider to SDK
|
|
183
|
+
*/
|
|
184
|
+
private setupEventForwarding(): void {
|
|
185
|
+
// Forward all relevant provider events to SDK events
|
|
186
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.CONNECT, (data: any) => {
|
|
187
|
+
// Already handled in connect() method
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.DISCONNECT, (data: any) => {
|
|
191
|
+
this.emit('disconnect', data);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.ERROR, (data: any) => {
|
|
195
|
+
this.emit('error', data);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
this.provider.on(EMBEDDED_PROVIDER_EVENTS.LOCK, (data: any) => {
|
|
199
|
+
this.emit('lock', data);
|
|
200
|
+
this.emit('disconnect', { reason: 'locked' });
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Destroy SDK and cleanup
|
|
206
|
+
*/
|
|
207
|
+
destroy(): void {
|
|
208
|
+
this.provider.destroy();
|
|
209
|
+
this.eventListeners.clear();
|
|
210
|
+
this.initialized = false;
|
|
211
|
+
this.connectInFlight = null;
|
|
212
|
+
this.lastConnectResult = null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private resolveMetadata(input?: ConnectMetadataInput): ConnectMetadataInput | undefined {
|
|
216
|
+
const defaultOrigin = typeof window !== 'undefined' ? window.location.origin : undefined;
|
|
217
|
+
if (!defaultOrigin && !input) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const appId = input?.appId || defaultOrigin;
|
|
222
|
+
const appUrl = this.resolveAppUrl(defaultOrigin, input?.appUrl);
|
|
223
|
+
const appName = input?.appName || this.deriveAppName(appUrl ?? appId);
|
|
224
|
+
|
|
225
|
+
const metadata: ConnectMetadataInput = {};
|
|
226
|
+
if (appId) metadata.appId = appId;
|
|
227
|
+
if (appUrl) metadata.appUrl = appUrl;
|
|
228
|
+
if (appName) metadata.appName = appName;
|
|
229
|
+
if (input?.imageUrl) metadata.imageUrl = input.imageUrl;
|
|
230
|
+
|
|
231
|
+
return metadata;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private resolveAppUrl(defaultOrigin?: string, providedUrl?: string): string | undefined {
|
|
235
|
+
const candidate = providedUrl || defaultOrigin;
|
|
236
|
+
if (!candidate) {
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const url = new URL(candidate, defaultOrigin);
|
|
242
|
+
return url.toString();
|
|
243
|
+
} catch {
|
|
244
|
+
return defaultOrigin;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private deriveAppName(source?: string): string | undefined {
|
|
249
|
+
if (!source) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const hostname = new URL(source).hostname;
|
|
255
|
+
return hostname || source;
|
|
256
|
+
} catch {
|
|
257
|
+
return source;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
public getThru(): Thru {
|
|
262
|
+
return this.thruClient;
|
|
263
|
+
}
|
|
264
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Main exports
|
|
2
|
+
export {
|
|
3
|
+
BrowserSDK,
|
|
4
|
+
type BrowserSDKConfig,
|
|
5
|
+
type SDKEvent,
|
|
6
|
+
type EventCallback,
|
|
7
|
+
type ConnectOptions,
|
|
8
|
+
} from './BrowserSDK';
|
|
9
|
+
|
|
10
|
+
// Re-export types from chain-interfaces for convenience
|
|
11
|
+
export type {
|
|
12
|
+
IThruChain,
|
|
13
|
+
WalletAddress,
|
|
14
|
+
ConnectResult,
|
|
15
|
+
SignMessageParams,
|
|
16
|
+
SignMessageResult,
|
|
17
|
+
} from '@thru/chain-interfaces';
|
|
18
|
+
|
|
19
|
+
// Re-export error codes from embedded-provider
|
|
20
|
+
export { ErrorCode } from '@thru/embedded-provider';
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: ['src/index.ts'],
|
|
5
|
+
format: ['esm'],
|
|
6
|
+
dts: true,
|
|
7
|
+
sourcemap: true,
|
|
8
|
+
clean: true,
|
|
9
|
+
treeshake: true,
|
|
10
|
+
platform: 'browser',
|
|
11
|
+
noExternal: ['@thru/chain-interfaces'],
|
|
12
|
+
external: [
|
|
13
|
+
'@thru/embedded-provider',
|
|
14
|
+
'@thru/protocol',
|
|
15
|
+
'crypto',
|
|
16
|
+
'buffer',
|
|
17
|
+
'stream',
|
|
18
|
+
'http',
|
|
19
|
+
'https',
|
|
20
|
+
'url',
|
|
21
|
+
'zlib',
|
|
22
|
+
],
|
|
23
|
+
});
|