@tangle-network/blueprint-ui 0.1.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,188 @@
1
+ import * as wagmi from 'wagmi';
2
+ import { Address, Hex } from 'viem';
3
+
4
+ /**
5
+ * Default Tangle Cloud origins. Consumers (agent-sandbox UI,
6
+ * trading-arena, future iframe blueprints) pass app-specific additions
7
+ * via `extraOrigins` rather than mutating this list.
8
+ */
9
+ declare const TANGLE_CLOUD_ORIGINS_DEFAULT: readonly ["https://cloud.tangle.tools", "https://develop.cloud.tangle.tools", "http://localhost:4300", "http://localhost:8888"];
10
+ /**
11
+ * Returns the parent origin to bridge to, or null when no trusted parent is
12
+ * detected. Caller should skip installing the bridge connector when this
13
+ * returns null.
14
+ *
15
+ * `extraOrigins` is the application's escape hatch for staging or dev
16
+ * deploys not covered by the default list. The library deliberately does
17
+ * not read environment variables itself (consumers may bundle for non-Vite
18
+ * runtimes); the consuming app threads `import.meta.env.VITE_*` or
19
+ * `process.env.*` in itself.
20
+ *
21
+ * Falls back to a `?parent=<origin>` query parameter when no referrer is
22
+ * present (some browsers strip referrer from cross-origin loads). Useful
23
+ * for dev embedding flows.
24
+ */
25
+ declare function detectTangleCloudParentOrigin(options?: {
26
+ extraOrigins?: readonly string[];
27
+ }): string | null;
28
+
29
+ type EventName = 'accountsChanged' | 'chainChanged' | 'connect' | 'disconnect' | 'message';
30
+ type Listener = (...args: unknown[]) => void;
31
+ type ParentBridgeOptions = {
32
+ /**
33
+ * Origin of the parent dapp that hosts this iframe. The provider posts to
34
+ * `window.parent` with this exact origin and rejects inbound messages from
35
+ * any other origin. Pass `'*'` only in development; production must pin to
36
+ * the real parent (`https://cloud.tangle.tools` or its develop equivalent).
37
+ */
38
+ parentOrigin: string;
39
+ /**
40
+ * Stable identifier for this iframe app. The parent includes this in the
41
+ * handshake ack so dev tooling can correlate logs across the two windows.
42
+ */
43
+ appId: string;
44
+ /**
45
+ * Optional ms timeout for each bridged request. Defaults to 60 seconds —
46
+ * long enough for a user to read + approve a signing prompt in the parent.
47
+ */
48
+ requestTimeoutMs?: number;
49
+ };
50
+ /**
51
+ * Detect iframe execution context. When this returns `false` the bridge
52
+ * connector should not be installed and the host app should fall back to its
53
+ * normal wallet config (ConnectKit + injected/walletConnect).
54
+ *
55
+ * `window.parent !== window` is the most reliable signal that works across
56
+ * sandbox-iframe contexts where direct property access to parent throws.
57
+ */
58
+ declare function isRunningInIframe(): boolean;
59
+ /**
60
+ * EIP-1193 provider backed by the Tangle Cloud iframe protocol. One instance
61
+ * lives per iframe app; the wagmi connector owns the singleton.
62
+ */
63
+ declare class ParentBridgeProvider {
64
+ private readonly options;
65
+ private listeners;
66
+ private pending;
67
+ private cachedAccount;
68
+ private cachedChainId;
69
+ private handshakeAcked;
70
+ private handshakeWaiters;
71
+ private installed;
72
+ constructor(options: ParentBridgeOptions);
73
+ /**
74
+ * Wire up the global message listener and send the initial handshake.
75
+ * Idempotent — safe to call repeatedly during reconnect attempts.
76
+ */
77
+ install(): void;
78
+ uninstall(): void;
79
+ request(req: {
80
+ method: string;
81
+ params?: unknown[];
82
+ }): Promise<unknown>;
83
+ on(event: EventName, listener: Listener): void;
84
+ removeListener(event: EventName, listener: Listener): void;
85
+ private postToParent;
86
+ private handleParentMessage;
87
+ private sendReadAccount;
88
+ private requestSignMessage;
89
+ private requestSignTransaction;
90
+ private requestSwitchChain;
91
+ private dispatch;
92
+ private resolvePending;
93
+ private ensureBootstrapped;
94
+ private updateAccount;
95
+ private updateChainId;
96
+ private emit;
97
+ /** Visible for tests + the connector's `getAccounts()` shortcut. */
98
+ getCachedAccount(): Address | null;
99
+ /** Visible for tests + the connector's `getChainId()` shortcut. */
100
+ getCachedChainId(): number | null;
101
+ }
102
+
103
+ type ParentBridgeConnectorOptions = ParentBridgeOptions;
104
+ declare function parentBridgeConnector(options: ParentBridgeConnectorOptions): wagmi.CreateConnectorFn<ParentBridgeProvider, Record<string, unknown>, Record<string, unknown>>;
105
+
106
+ declare const TANGLE_IFRAME_PROTOCOL_VERSION: "1";
107
+ declare const TANGLE_IFRAME_PROTOCOL_PREFIX = "tangle.app.";
108
+ type HandshakeRequest = {
109
+ kind: 'tangle.app.handshake';
110
+ appId: string;
111
+ version: typeof TANGLE_IFRAME_PROTOCOL_VERSION;
112
+ };
113
+ type ReadAccountRequest = {
114
+ kind: 'tangle.app.readAccount';
115
+ correlationId: string;
116
+ };
117
+ type SwitchChainRequest = {
118
+ kind: 'tangle.app.switchChain';
119
+ correlationId: string;
120
+ chainId: number;
121
+ };
122
+ type SignMessageRequest = {
123
+ kind: 'tangle.app.signMessage';
124
+ correlationId: string;
125
+ chainId: number;
126
+ message: string;
127
+ };
128
+ type SignTransactionRequest = {
129
+ kind: 'tangle.app.signTransaction';
130
+ correlationId: string;
131
+ chainId: number;
132
+ to: Address;
133
+ data: Hex;
134
+ value?: string;
135
+ };
136
+ type HandshakeAck = {
137
+ kind: 'tangle.app.handshakeAck';
138
+ appId: string;
139
+ protocolVersion: typeof TANGLE_IFRAME_PROTOCOL_VERSION;
140
+ };
141
+ type ResultEnvelope<T> = {
142
+ correlationId: string;
143
+ } & ({
144
+ ok: true;
145
+ data: T;
146
+ } | {
147
+ ok: false;
148
+ error: string;
149
+ });
150
+ type ReadAccountResult = {
151
+ kind: 'tangle.app.readAccountResult';
152
+ } & ResultEnvelope<{
153
+ account: Address;
154
+ chainId: number;
155
+ }>;
156
+ type SwitchChainResult = {
157
+ kind: 'tangle.app.switchChainResult';
158
+ } & ResultEnvelope<{
159
+ chainId: number;
160
+ }>;
161
+ type SignMessageResult = {
162
+ kind: 'tangle.app.signMessageResult';
163
+ } & ResultEnvelope<{
164
+ signature: Hex;
165
+ }>;
166
+ type SignTransactionResult = {
167
+ kind: 'tangle.app.signTransactionResult';
168
+ } & ResultEnvelope<{
169
+ txHash: Hex;
170
+ }>;
171
+ type AccountChanged = {
172
+ kind: 'tangle.app.accountChanged';
173
+ account: Address | null;
174
+ };
175
+ type ChainChanged = {
176
+ kind: 'tangle.app.chainChanged';
177
+ chainId: number;
178
+ };
179
+ type ParentMessage = HandshakeAck | ReadAccountResult | SwitchChainResult | SignMessageResult | SignTransactionResult | AccountChanged | ChainChanged;
180
+ declare const NO_WALLET_ADDRESS = "0x0000000000000000000000000000000000000000";
181
+ /**
182
+ * Cryptographically-random ASCII correlation id matching the parent's
183
+ * validator regex (`/^[\w.\-:]+$/`, max length 128). The connector keeps a
184
+ * Map<correlationId, Resolver> so each request resolves independently.
185
+ */
186
+ declare function makeCorrelationId(prefix: string): string;
187
+
188
+ export { type AccountChanged, type ChainChanged, type HandshakeAck, type HandshakeRequest, NO_WALLET_ADDRESS, type ParentBridgeConnectorOptions, type ParentBridgeOptions, ParentBridgeProvider, type ParentMessage, type ReadAccountRequest, type ReadAccountResult, type SignMessageRequest, type SignMessageResult, type SignTransactionRequest, type SignTransactionResult, type SwitchChainRequest, type SwitchChainResult, TANGLE_CLOUD_ORIGINS_DEFAULT, TANGLE_IFRAME_PROTOCOL_PREFIX, TANGLE_IFRAME_PROTOCOL_VERSION, detectTangleCloudParentOrigin, isRunningInIframe, makeCorrelationId, parentBridgeConnector };
@@ -0,0 +1,466 @@
1
+ // src/wallet/detectParentOrigin.ts
2
+ var TANGLE_CLOUD_ORIGINS_DEFAULT = Object.freeze([
3
+ "https://cloud.tangle.tools",
4
+ "https://develop.cloud.tangle.tools",
5
+ // Local dev (Vite default port for tangle-cloud + Netlify dev preview).
6
+ "http://localhost:4300",
7
+ "http://localhost:8888"
8
+ ]);
9
+ function originFromReferrer() {
10
+ if (typeof document === "undefined") return null;
11
+ const ref = document.referrer;
12
+ if (!ref) return null;
13
+ try {
14
+ return new URL(ref).origin;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ function detectTangleCloudParentOrigin(options = {}) {
20
+ if (typeof window === "undefined" || window.parent === window) {
21
+ return null;
22
+ }
23
+ const allowlist = /* @__PURE__ */ new Set([
24
+ ...TANGLE_CLOUD_ORIGINS_DEFAULT,
25
+ ...options.extraOrigins ?? []
26
+ ]);
27
+ const referrerOrigin = originFromReferrer();
28
+ if (referrerOrigin && allowlist.has(referrerOrigin)) {
29
+ return referrerOrigin;
30
+ }
31
+ try {
32
+ const url = new URL(window.location.href);
33
+ const explicit = url.searchParams.get("parent");
34
+ if (explicit && allowlist.has(explicit)) return explicit;
35
+ } catch {
36
+ }
37
+ return null;
38
+ }
39
+
40
+ // src/wallet/parentBridgeConnector.ts
41
+ import { createConnector } from "wagmi";
42
+
43
+ // src/wallet/parentBridgeProtocol.ts
44
+ var TANGLE_IFRAME_PROTOCOL_VERSION = "1";
45
+ var TANGLE_IFRAME_PROTOCOL_PREFIX = "tangle.app.";
46
+ var NO_WALLET_ADDRESS = "0x0000000000000000000000000000000000000000";
47
+ function makeCorrelationId(prefix) {
48
+ const random = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : Math.random().toString(36).slice(2) + Date.now().toString(36);
49
+ return `${prefix}.${random}`;
50
+ }
51
+
52
+ // src/wallet/parentBridgeProvider.ts
53
+ var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
54
+ function isRunningInIframe() {
55
+ if (typeof window === "undefined") return false;
56
+ try {
57
+ return window.parent !== void 0 && window.parent !== window;
58
+ } catch {
59
+ return true;
60
+ }
61
+ }
62
+ var ParentBridgeProvider = class {
63
+ constructor(options) {
64
+ this.options = options;
65
+ }
66
+ options;
67
+ listeners = /* @__PURE__ */ new Map();
68
+ pending = /* @__PURE__ */ new Map();
69
+ cachedAccount = null;
70
+ cachedChainId = null;
71
+ handshakeAcked = false;
72
+ handshakeWaiters = [];
73
+ installed = false;
74
+ /**
75
+ * Wire up the global message listener and send the initial handshake.
76
+ * Idempotent — safe to call repeatedly during reconnect attempts.
77
+ */
78
+ install() {
79
+ if (this.installed || typeof window === "undefined") return;
80
+ this.installed = true;
81
+ window.addEventListener("message", this.handleParentMessage);
82
+ this.postToParent({
83
+ kind: "tangle.app.handshake",
84
+ appId: this.options.appId,
85
+ version: TANGLE_IFRAME_PROTOCOL_VERSION
86
+ });
87
+ }
88
+ uninstall() {
89
+ if (!this.installed || typeof window === "undefined") return;
90
+ this.installed = false;
91
+ window.removeEventListener("message", this.handleParentMessage);
92
+ for (const [, pending] of this.pending) {
93
+ pending.reject(new Error("Parent bridge uninstalled"));
94
+ }
95
+ this.pending.clear();
96
+ }
97
+ // ── EIP-1193 surface ────────────────────────────────────────────────────
98
+ async request(req) {
99
+ const method = req.method;
100
+ const params = req.params ?? [];
101
+ switch (method) {
102
+ case "eth_chainId": {
103
+ await this.ensureBootstrapped();
104
+ return this.cachedChainId !== null ? `0x${this.cachedChainId.toString(16)}` : "0x0";
105
+ }
106
+ case "eth_accounts":
107
+ case "eth_requestAccounts": {
108
+ await this.ensureBootstrapped();
109
+ return this.cachedAccount !== null ? [this.cachedAccount] : [];
110
+ }
111
+ case "personal_sign": {
112
+ const [message, _signer] = params;
113
+ return this.requestSignMessage(message);
114
+ }
115
+ case "eth_signTypedData_v4": {
116
+ throw bridgeError(
117
+ 4200,
118
+ "eth_signTypedData_v4 is not supported by the parent-bridge protocol yet."
119
+ );
120
+ }
121
+ case "eth_sendTransaction": {
122
+ const [tx] = params;
123
+ if (!tx?.to || !tx.data) {
124
+ throw bridgeError(-32602, "eth_sendTransaction requires `to` and `data`.");
125
+ }
126
+ return this.requestSignTransaction(tx);
127
+ }
128
+ case "wallet_switchEthereumChain": {
129
+ const [{ chainId }] = params;
130
+ const numeric = Number.parseInt(chainId, 16);
131
+ if (!Number.isFinite(numeric) || numeric <= 0) {
132
+ throw bridgeError(-32602, `Invalid chainId: ${chainId}`);
133
+ }
134
+ await this.requestSwitchChain(numeric);
135
+ return null;
136
+ }
137
+ case "wallet_addEthereumChain": {
138
+ throw bridgeError(
139
+ 4200,
140
+ "wallet_addEthereumChain is not supported through the parent bridge."
141
+ );
142
+ }
143
+ default:
144
+ throw bridgeError(4200, `Method ${method} not supported by parent bridge.`);
145
+ }
146
+ }
147
+ on(event, listener) {
148
+ const set = this.listeners.get(event) ?? /* @__PURE__ */ new Set();
149
+ set.add(listener);
150
+ this.listeners.set(event, set);
151
+ }
152
+ removeListener(event, listener) {
153
+ this.listeners.get(event)?.delete(listener);
154
+ }
155
+ // ── Internal: dispatch + book-keeping ───────────────────────────────────
156
+ postToParent(message) {
157
+ if (typeof window === "undefined") return;
158
+ try {
159
+ window.parent.postMessage(message, this.options.parentOrigin);
160
+ } catch {
161
+ }
162
+ }
163
+ handleParentMessage = (event) => {
164
+ if (event.origin !== this.options.parentOrigin) return;
165
+ const data = event.data;
166
+ if (typeof data !== "object" || data === null) return;
167
+ const message = data;
168
+ switch (message.kind) {
169
+ case "tangle.app.handshakeAck":
170
+ this.handshakeAcked = true;
171
+ for (const resolve of this.handshakeWaiters) resolve();
172
+ this.handshakeWaiters = [];
173
+ this.sendReadAccount().catch(() => {
174
+ });
175
+ return;
176
+ case "tangle.app.readAccountResult":
177
+ this.resolvePending(message);
178
+ if (message.ok) {
179
+ this.updateAccount(
180
+ message.data.account === NO_WALLET_ADDRESS ? null : message.data.account
181
+ );
182
+ this.updateChainId(message.data.chainId);
183
+ }
184
+ return;
185
+ case "tangle.app.switchChainResult":
186
+ this.resolvePending(message);
187
+ if (message.ok) this.updateChainId(message.data.chainId);
188
+ return;
189
+ case "tangle.app.signMessageResult":
190
+ case "tangle.app.signTransactionResult":
191
+ this.resolvePending(message);
192
+ return;
193
+ case "tangle.app.accountChanged":
194
+ this.updateAccount(message.account);
195
+ return;
196
+ case "tangle.app.chainChanged":
197
+ this.updateChainId(message.chainId);
198
+ return;
199
+ }
200
+ };
201
+ sendReadAccount() {
202
+ return this.dispatch({
203
+ kind: "tangle.app.readAccount",
204
+ expectedKind: "tangle.app.readAccountResult"
205
+ });
206
+ }
207
+ requestSignMessage(message) {
208
+ const chainId = this.cachedChainId ?? 1;
209
+ return this.dispatch({
210
+ kind: "tangle.app.signMessage",
211
+ expectedKind: "tangle.app.signMessageResult",
212
+ payload: { chainId, message }
213
+ }).then((data) => data.signature);
214
+ }
215
+ requestSignTransaction(tx) {
216
+ const chainId = this.cachedChainId ?? 1;
217
+ const value = typeof tx.value === "string" && tx.value.startsWith("0x") ? BigInt(tx.value).toString(10) : typeof tx.value === "string" ? tx.value : void 0;
218
+ return this.dispatch({
219
+ kind: "tangle.app.signTransaction",
220
+ expectedKind: "tangle.app.signTransactionResult",
221
+ payload: {
222
+ chainId,
223
+ to: tx.to,
224
+ data: tx.data,
225
+ ...value !== void 0 ? { value } : {}
226
+ }
227
+ }).then((data) => data.txHash);
228
+ }
229
+ requestSwitchChain(chainId) {
230
+ return this.dispatch({
231
+ kind: "tangle.app.switchChain",
232
+ expectedKind: "tangle.app.switchChainResult",
233
+ payload: { chainId }
234
+ }).then((data) => data.chainId);
235
+ }
236
+ async dispatch(req) {
237
+ await this.ensureBootstrapped();
238
+ const correlationId = makeCorrelationId(req.kind);
239
+ const timeout = this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
240
+ return new Promise((resolve, reject) => {
241
+ const timer = window.setTimeout(() => {
242
+ this.pending.delete(correlationId);
243
+ reject(bridgeError(4900, `Parent did not respond to ${req.kind} within ${timeout}ms`));
244
+ }, timeout);
245
+ this.pending.set(correlationId, {
246
+ resolve: (v) => {
247
+ window.clearTimeout(timer);
248
+ resolve(v);
249
+ },
250
+ reject: (e) => {
251
+ window.clearTimeout(timer);
252
+ reject(e);
253
+ },
254
+ expectedKind: req.expectedKind
255
+ });
256
+ this.postToParent({
257
+ kind: req.kind,
258
+ correlationId,
259
+ ...req.payload ?? {}
260
+ });
261
+ });
262
+ }
263
+ resolvePending(message) {
264
+ const entry = this.pending.get(message.correlationId);
265
+ if (!entry) return;
266
+ this.pending.delete(message.correlationId);
267
+ if (entry.expectedKind !== message.kind) {
268
+ entry.reject(
269
+ bridgeError(
270
+ -32e3,
271
+ `Parent replied with ${message.kind} but ${entry.expectedKind} was expected`
272
+ )
273
+ );
274
+ return;
275
+ }
276
+ if (message.ok) {
277
+ entry.resolve(message.data);
278
+ } else {
279
+ entry.reject(bridgeError(4001, message.error));
280
+ }
281
+ }
282
+ async ensureBootstrapped() {
283
+ if (this.handshakeAcked) return;
284
+ this.install();
285
+ await new Promise((resolve) => {
286
+ this.handshakeWaiters.push(resolve);
287
+ const retry = window.setInterval(() => {
288
+ if (this.handshakeAcked) {
289
+ window.clearInterval(retry);
290
+ return;
291
+ }
292
+ this.postToParent({
293
+ kind: "tangle.app.handshake",
294
+ appId: this.options.appId,
295
+ version: TANGLE_IFRAME_PROTOCOL_VERSION
296
+ });
297
+ }, 500);
298
+ window.setTimeout(() => window.clearInterval(retry), 1e4);
299
+ });
300
+ }
301
+ updateAccount(next) {
302
+ if (this.cachedAccount === next) return;
303
+ const prev = this.cachedAccount;
304
+ this.cachedAccount = next;
305
+ if (next === null && prev !== null) {
306
+ this.emit("disconnect");
307
+ this.emit("accountsChanged", []);
308
+ } else if (next !== null) {
309
+ this.emit("accountsChanged", [next]);
310
+ if (prev === null) {
311
+ this.emit("connect", { chainId: this.cachedChainId ?? 0 });
312
+ }
313
+ }
314
+ }
315
+ updateChainId(next) {
316
+ if (this.cachedChainId === next) return;
317
+ this.cachedChainId = next;
318
+ this.emit("chainChanged", `0x${next.toString(16)}`);
319
+ }
320
+ emit(event, ...args) {
321
+ const set = this.listeners.get(event);
322
+ if (!set) return;
323
+ for (const listener of [...set]) {
324
+ try {
325
+ listener(...args);
326
+ } catch {
327
+ }
328
+ }
329
+ }
330
+ // ── Test seams ──────────────────────────────────────────────────────────
331
+ /** Visible for tests + the connector's `getAccounts()` shortcut. */
332
+ getCachedAccount() {
333
+ return this.cachedAccount;
334
+ }
335
+ /** Visible for tests + the connector's `getChainId()` shortcut. */
336
+ getCachedChainId() {
337
+ return this.cachedChainId;
338
+ }
339
+ };
340
+ function bridgeError(code, message) {
341
+ const err = new Error(message);
342
+ err.code = code;
343
+ return err;
344
+ }
345
+
346
+ // src/wallet/parentBridgeConnector.ts
347
+ function parentBridgeConnector(options) {
348
+ let provider;
349
+ let installed = false;
350
+ return createConnector((config) => {
351
+ const ensureProvider = () => {
352
+ if (!provider) provider = new ParentBridgeProvider(options);
353
+ if (!installed) {
354
+ provider.install();
355
+ installed = true;
356
+ provider.on("accountsChanged", (accounts) => {
357
+ config.emitter.emit("change", {
358
+ accounts: Array.isArray(accounts) ? accounts : []
359
+ });
360
+ });
361
+ provider.on("chainChanged", (chainIdHex) => {
362
+ const chainId = typeof chainIdHex === "string" ? Number.parseInt(chainIdHex, 16) : Number(chainIdHex);
363
+ if (Number.isFinite(chainId)) {
364
+ config.emitter.emit("change", { chainId });
365
+ }
366
+ });
367
+ provider.on("disconnect", () => {
368
+ config.emitter.emit("disconnect");
369
+ });
370
+ }
371
+ return provider;
372
+ };
373
+ return {
374
+ id: "tangleParentBridge",
375
+ name: "Tangle Cloud",
376
+ type: "parentBridge",
377
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
378
+ async connect() {
379
+ const p = ensureProvider();
380
+ const accountsResult = await p.request({
381
+ method: "eth_requestAccounts"
382
+ });
383
+ const chainIdHex = await p.request({ method: "eth_chainId" });
384
+ const chainId = Number.parseInt(chainIdHex, 16);
385
+ return {
386
+ accounts: accountsResult,
387
+ chainId: Number.isFinite(chainId) ? chainId : 0
388
+ };
389
+ },
390
+ async disconnect() {
391
+ if (provider) provider.uninstall();
392
+ installed = false;
393
+ provider = void 0;
394
+ },
395
+ async getAccounts() {
396
+ const p = ensureProvider();
397
+ const cached = p.getCachedAccount();
398
+ if (cached) return [cached];
399
+ const accounts = await p.request({
400
+ method: "eth_accounts"
401
+ });
402
+ return accounts;
403
+ },
404
+ async getChainId() {
405
+ const p = ensureProvider();
406
+ const cached = p.getCachedChainId();
407
+ if (cached !== null) return cached;
408
+ const chainIdHex = await p.request({ method: "eth_chainId" });
409
+ const chainId = Number.parseInt(chainIdHex, 16);
410
+ return Number.isFinite(chainId) ? chainId : 0;
411
+ },
412
+ async getProvider() {
413
+ return ensureProvider();
414
+ },
415
+ async isAuthorized() {
416
+ try {
417
+ const p = ensureProvider();
418
+ const accounts = await p.request({
419
+ method: "eth_accounts"
420
+ });
421
+ return accounts.length > 0;
422
+ } catch {
423
+ return false;
424
+ }
425
+ },
426
+ async switchChain({ chainId }) {
427
+ const p = ensureProvider();
428
+ await p.request({
429
+ method: "wallet_switchEthereumChain",
430
+ params: [{ chainId: `0x${chainId.toString(16)}` }]
431
+ });
432
+ const chain = config.chains.find((c) => c.id === chainId);
433
+ if (!chain) {
434
+ throw new Error(`Chain ${chainId} not configured for this app`);
435
+ }
436
+ return chain;
437
+ },
438
+ onAccountsChanged(accounts) {
439
+ config.emitter.emit("change", {
440
+ accounts
441
+ });
442
+ },
443
+ onChainChanged(chainIdHex) {
444
+ const chainId = Number.parseInt(chainIdHex, 16);
445
+ if (Number.isFinite(chainId)) {
446
+ config.emitter.emit("change", { chainId });
447
+ }
448
+ },
449
+ onDisconnect() {
450
+ config.emitter.emit("disconnect");
451
+ }
452
+ };
453
+ });
454
+ }
455
+ export {
456
+ NO_WALLET_ADDRESS,
457
+ ParentBridgeProvider,
458
+ TANGLE_CLOUD_ORIGINS_DEFAULT,
459
+ TANGLE_IFRAME_PROTOCOL_PREFIX,
460
+ TANGLE_IFRAME_PROTOCOL_VERSION,
461
+ detectTangleCloudParentOrigin,
462
+ isRunningInIframe,
463
+ makeCorrelationId,
464
+ parentBridgeConnector
465
+ };
466
+ //# sourceMappingURL=index.js.map