@swype-org/deposit 0.3.13 → 0.3.14

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,5 +1,5 @@
1
- import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-CCi4cpnQ.js';
2
- export { C as CheckoutConfig, e as CheckoutError, f as CheckoutErrorCode, g as CheckoutStatus, h as DepositErrorCode, S as SignerFunction, i as SignerRequest, j as SignerResponse, T as TransferSummary, k as getDisplayMessage } from './types-CCi4cpnQ.js';
1
+ import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-DYsZwNXq.js';
2
+ export { C as CheckoutConfig, e as CheckoutError, f as CheckoutErrorCode, g as CheckoutStatus, h as DepositErrorCode, S as SignerFunction, i as SignerRequest, j as SignerResponse, T as TransferSummary, k as getDisplayMessage } from './types-DYsZwNXq.js';
3
3
 
4
4
  declare const DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
5
5
  type EventMap = {
@@ -73,6 +73,162 @@ declare class Deposit {
73
73
  /** @deprecated Use {@link Deposit} instead. */
74
74
  declare const Checkout: typeof Deposit;
75
75
 
76
+ /** Current wire-protocol version. Bump on breaking changes. */
77
+ declare const BRIDGE_PROTOCOL_VERSION = 1;
78
+ interface EIP6963ProviderInfo {
79
+ uuid: string;
80
+ name: string;
81
+ icon: string;
82
+ rdns: string;
83
+ }
84
+ interface EIP1193RequestArgs {
85
+ method: string;
86
+ params?: unknown[] | Record<string, unknown>;
87
+ }
88
+ interface EIP1193Provider {
89
+ request(args: EIP1193RequestArgs): Promise<unknown>;
90
+ on?: (event: string, listener: (...args: unknown[]) => void) => unknown;
91
+ removeListener?: (event: string, listener: (...args: unknown[]) => void) => unknown;
92
+ }
93
+ interface EIP6963ProviderDetail {
94
+ info: EIP6963ProviderInfo;
95
+ provider: EIP1193Provider;
96
+ }
97
+ /** Iframe → Parent: handshake, sent once on mount. */
98
+ interface BridgeHelloMessage {
99
+ type: 'blink:bridge-hello';
100
+ protocolVersion: number;
101
+ }
102
+ /** Parent → Iframe: list of installed wallets the iframe can borrow. */
103
+ interface WalletsAdvertisedMessage {
104
+ type: 'blink:wallets-advertised';
105
+ protocolVersion: number;
106
+ wallets: AdvertisedWallet[];
107
+ }
108
+ interface AdvertisedWallet {
109
+ uuid: string;
110
+ rdns: string;
111
+ name: string;
112
+ icon: string;
113
+ }
114
+ /** Iframe → Parent: invoke a JSON-RPC method on a top-frame wallet. */
115
+ interface RpcRequestMessage {
116
+ type: 'blink:rpc-request';
117
+ protocolVersion: number;
118
+ uuid: string;
119
+ id: string;
120
+ method: string;
121
+ params?: unknown[] | Record<string, unknown>;
122
+ }
123
+ /** Parent → Iframe: result of a previous `RpcRequestMessage`. */
124
+ interface RpcResponseMessage {
125
+ type: 'blink:rpc-response';
126
+ protocolVersion: number;
127
+ id: string;
128
+ result?: unknown;
129
+ error?: {
130
+ code: number;
131
+ message: string;
132
+ data?: unknown;
133
+ };
134
+ }
135
+ /** Parent → Iframe: forwarded EIP-1193 event from a top-frame wallet. */
136
+ interface RpcEventMessage {
137
+ type: 'blink:rpc-event';
138
+ protocolVersion: number;
139
+ uuid: string;
140
+ event: string;
141
+ args: unknown[];
142
+ }
143
+ /**
144
+ * Iframe → Parent: ask "which advertised wallet has any of these flags
145
+ * (e.g. `isUniswapWallet`) set as a truthy property on its provider?".
146
+ * Used to disambiguate Reown registry entries that lack `rdns` (e.g.
147
+ * Uniswap, where Reown only ships `injected[].injectedId:
148
+ * 'isUniswapWallet'`). The parent reads `provider[flag]` defensively
149
+ * for each advertised provider and returns the first hit, or null.
150
+ *
151
+ * The parent answers each request once; the response is matched by
152
+ * `id`. Cost is local property reads on already-discovered providers —
153
+ * no network and no cross-frame I/O beyond the postMessage round-trip.
154
+ */
155
+ interface ResolveByFlagRequestMessage {
156
+ type: 'blink:resolve-by-flag';
157
+ protocolVersion: number;
158
+ /** Request id, mirrored on the response so the iframe can route it. */
159
+ id: string;
160
+ /** Flag names to test in order; first truthy property wins. */
161
+ flags: string[];
162
+ }
163
+ /** Parent → Iframe: result of a previous `ResolveByFlagRequestMessage`. */
164
+ interface ResolveByFlagResponseMessage {
165
+ type: 'blink:resolve-by-flag-response';
166
+ protocolVersion: number;
167
+ id: string;
168
+ /** `null` when no advertised provider had any flag set. */
169
+ match: ResolveByFlagMatch | null;
170
+ }
171
+ interface ResolveByFlagMatch {
172
+ /** EIP-6963 `rdns` of the matched provider. */
173
+ rdns: string;
174
+ /** EIP-6963 `uuid` of the matched provider. */
175
+ uuid: string;
176
+ /** Which flag matched first (lets the caller log/telemeter). */
177
+ flag: string;
178
+ }
179
+ type BridgeMessage = BridgeHelloMessage | WalletsAdvertisedMessage | RpcRequestMessage | RpcResponseMessage | RpcEventMessage | ResolveByFlagRequestMessage | ResolveByFlagResponseMessage;
180
+ declare const ALLOWED_RPC_METHODS: Set<string>;
181
+ declare function parseBridgeMessage(data: unknown): BridgeMessage | null;
182
+
183
+ interface RegisteredProvider {
184
+ info: EIP6963ProviderInfo;
185
+ provider: EIP1193Provider;
186
+ }
187
+ interface WalletDiscovererHandle {
188
+ /** Snapshot of currently-registered providers. */
189
+ list(): RegisteredProvider[];
190
+ /** Look up a single provider by EIP-6963 uuid. */
191
+ get(uuid: string): EIP1193Provider | undefined;
192
+ /** Subscribe to registry changes. Returns an unsubscribe callback. */
193
+ subscribe(listener: (snapshot: RegisteredProvider[]) => void): () => void;
194
+ /**
195
+ * Re-dispatch `eip6963:requestProvider`. Wallets that wired up after
196
+ * page load (or after the initial sweep) will re-announce in response.
197
+ */
198
+ requestProviders(): void;
199
+ /** Tear down listeners. After this, `list()` returns `[]`. */
200
+ destroy(): void;
201
+ }
202
+ /**
203
+ * Start discovering EIP-6963 providers in the current (top-level) frame.
204
+ *
205
+ * Safe to call multiple times — each handle owns its own listeners and
206
+ * registry; calling `destroy()` releases both. In practice, `createIframe`
207
+ * spins one handle per modal open.
208
+ */
209
+ declare function createWalletDiscoverer(): WalletDiscovererHandle;
210
+
211
+ interface RpcHostHandle {
212
+ /** Tear down listeners and unsubscribe from all bridged providers. */
213
+ detach(): void;
214
+ }
215
+ interface RpcHostOptions {
216
+ /** Cross-origin iframe window we're talking to. */
217
+ iframeWindow: Window;
218
+ /** Origin of the iframe — origin-pin all postMessage send/receive. */
219
+ iframeOrigin: string;
220
+ /** Discoverer providing the EIP-6963 provider registry. */
221
+ discoverer: WalletDiscovererHandle;
222
+ /** Optional debug logger; defaults to a no-op. */
223
+ log?: (message: string, data?: Record<string, unknown>) => void;
224
+ }
225
+ /**
226
+ * Attach an RPC host to the given iframe. Listens on `window` for
227
+ * messages from the iframe and routes allowlisted JSON-RPC calls to the
228
+ * matching top-frame EIP-1193 provider.
229
+ */
230
+ declare function attachRpcHost(options: RpcHostOptions): RpcHostHandle;
231
+
76
232
  declare const VERSION = "0.3.0";
77
233
 
78
- export { Checkout, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositConfig, DepositError, DepositRequest, DepositResult, DepositStatus, VERSION };
234
+ export { ALLOWED_RPC_METHODS, type AdvertisedWallet, BRIDGE_PROTOCOL_VERSION, type EIP1193Provider as BridgeEIP1193Provider, type BridgeHelloMessage, type BridgeMessage, Checkout, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositConfig, DepositError, DepositRequest, DepositResult, DepositStatus, type EIP6963ProviderDetail, type EIP6963ProviderInfo, type RegisteredProvider, type RpcEventMessage, type RpcHostHandle, type RpcHostOptions, type RpcRequestMessage, type RpcResponseMessage, VERSION, type WalletDiscovererHandle, type WalletsAdvertisedMessage, attachRpcHost, createWalletDiscoverer, parseBridgeMessage };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Checkout, CheckoutError, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositError, getDisplayMessage } from './chunk-7Y4RWJI3.js';
1
+ export { ALLOWED_RPC_METHODS, BRIDGE_PROTOCOL_VERSION, Checkout, CheckoutError, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositError, attachRpcHost, createWalletDiscoverer, getDisplayMessage, parseBridgeMessage } from './chunk-XYI3ZPQD.js';
2
2
 
3
3
  // src/index.ts
4
4
  var VERSION = "0.3.0";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAgBO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["export { Deposit, Checkout, DEFAULT_WEBVIEW_BASE_URL } from './checkout.ts';\nexport { DepositError, CheckoutError, getDisplayMessage } from './errors.ts';\nexport type { DepositErrorCode, CheckoutErrorCode } from './errors.ts';\nexport type {\n DepositConfig,\n CheckoutConfig,\n DepositStatus,\n CheckoutStatus,\n DepositRequest,\n DepositResult,\n SignerFunction,\n SignerRequest,\n SignerResponse,\n TransferSummary,\n} from './types.ts';\n\nexport const VERSION = '0.3.0';\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AA2CO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["export { Deposit, Checkout, DEFAULT_WEBVIEW_BASE_URL } from './checkout.ts';\nexport { DepositError, CheckoutError, getDisplayMessage } from './errors.ts';\nexport type { DepositErrorCode, CheckoutErrorCode } from './errors.ts';\nexport type {\n DepositConfig,\n CheckoutConfig,\n DepositStatus,\n CheckoutStatus,\n DepositRequest,\n DepositResult,\n SignerFunction,\n SignerRequest,\n SignerResponse,\n TransferSummary,\n} from './types.ts';\n\n// ── Wallet bridge (advanced) ──────────────────────────────────────────\n// Internal building blocks for the top-frame → iframe wallet bridge.\n// Default merchant integrations don't need these — `createIframe()` wires\n// them automatically. Re-exported so monorepo tests and any merchant\n// custom-iframe wrapper can poke at the protocol shapes.\nexport { createWalletDiscoverer } from './walletBridge/discover.ts';\nexport type { WalletDiscovererHandle, RegisteredProvider } from './walletBridge/discover.ts';\nexport { attachRpcHost } from './walletBridge/rpcHost.ts';\nexport type { RpcHostHandle, RpcHostOptions } from './walletBridge/rpcHost.ts';\nexport {\n ALLOWED_RPC_METHODS,\n BRIDGE_PROTOCOL_VERSION,\n parseBridgeMessage,\n} from './walletBridge/protocol.ts';\nexport type {\n AdvertisedWallet,\n BridgeMessage,\n BridgeHelloMessage,\n WalletsAdvertisedMessage,\n RpcRequestMessage,\n RpcResponseMessage,\n RpcEventMessage,\n EIP1193Provider as BridgeEIP1193Provider,\n EIP6963ProviderInfo,\n EIP6963ProviderDetail,\n} from './walletBridge/protocol.ts';\n\nexport const VERSION = '0.3.0';\n"]}
package/dist/react.cjs CHANGED
@@ -94,6 +94,396 @@ function parseCloseRequest(data) {
94
94
  return { type: "blink:close-request" };
95
95
  }
96
96
 
97
+ // src/walletBridge/discover.ts
98
+ function createWalletDiscoverer() {
99
+ if (typeof window === "undefined") {
100
+ return makeNoopHandle();
101
+ }
102
+ const registry = /* @__PURE__ */ new Map();
103
+ const listeners = /* @__PURE__ */ new Set();
104
+ let destroyed = false;
105
+ const onAnnounce = (event) => {
106
+ if (destroyed) return;
107
+ const detail = event.detail;
108
+ if (!isValidProviderDetail(detail)) {
109
+ console.info("[blink-bridge:parent] dropping malformed EIP-6963 announcement", {
110
+ rawInfo: event.detail && event.detail.info
111
+ });
112
+ return;
113
+ }
114
+ const existing = registry.get(detail.info.uuid);
115
+ if (existing && existing.provider === detail.provider) {
116
+ return;
117
+ }
118
+ console.info("[blink-bridge:parent] EIP-6963 announceProvider", {
119
+ rdns: detail.info.rdns,
120
+ name: detail.info.name,
121
+ uuid: detail.info.uuid
122
+ });
123
+ registry.set(detail.info.uuid, {
124
+ info: { ...detail.info },
125
+ provider: detail.provider
126
+ });
127
+ notify();
128
+ };
129
+ window.addEventListener("eip6963:announceProvider", onAnnounce);
130
+ requestProviders();
131
+ const RESWEEP_INTERVALS_MS = [500, 1500, 3e3, 6e3];
132
+ const reSweepTimers = [];
133
+ for (const ms of RESWEEP_INTERVALS_MS) {
134
+ reSweepTimers.push(
135
+ setTimeout(() => {
136
+ if (!destroyed) requestProviders();
137
+ }, ms)
138
+ );
139
+ }
140
+ function requestProviders() {
141
+ try {
142
+ window.dispatchEvent(new Event("eip6963:requestProvider"));
143
+ } catch {
144
+ }
145
+ }
146
+ function notify() {
147
+ const snapshot = list();
148
+ for (const listener of listeners) {
149
+ try {
150
+ listener(snapshot);
151
+ } catch {
152
+ }
153
+ }
154
+ }
155
+ function list() {
156
+ return [...registry.values()];
157
+ }
158
+ return {
159
+ list,
160
+ get(uuid) {
161
+ return registry.get(uuid)?.provider;
162
+ },
163
+ subscribe(listener) {
164
+ listeners.add(listener);
165
+ return () => {
166
+ listeners.delete(listener);
167
+ };
168
+ },
169
+ requestProviders,
170
+ destroy() {
171
+ if (destroyed) return;
172
+ destroyed = true;
173
+ window.removeEventListener("eip6963:announceProvider", onAnnounce);
174
+ for (const t of reSweepTimers) clearTimeout(t);
175
+ registry.clear();
176
+ listeners.clear();
177
+ }
178
+ };
179
+ }
180
+ function makeNoopHandle() {
181
+ return {
182
+ list: () => [],
183
+ get: () => void 0,
184
+ subscribe: () => () => {
185
+ },
186
+ requestProviders: () => {
187
+ },
188
+ destroy: () => {
189
+ }
190
+ };
191
+ }
192
+ function isValidProviderDetail(value) {
193
+ if (!value || typeof value !== "object") return false;
194
+ const detail = value;
195
+ const info = detail.info;
196
+ const provider = detail.provider;
197
+ if (!info || !provider) return false;
198
+ if (typeof info.uuid !== "string" || info.uuid.length === 0) return false;
199
+ if (typeof info.name !== "string") return false;
200
+ if (typeof info.rdns !== "string") return false;
201
+ if (typeof provider.request !== "function") return false;
202
+ return true;
203
+ }
204
+
205
+ // src/walletBridge/protocol.ts
206
+ var BRIDGE_PROTOCOL_VERSION = 1;
207
+ var ALLOWED_RPC_METHODS = /* @__PURE__ */ new Set([
208
+ // Read
209
+ "eth_accounts",
210
+ "eth_blockNumber",
211
+ "eth_call",
212
+ "eth_chainId",
213
+ "eth_estimateGas",
214
+ "eth_gasPrice",
215
+ "eth_getBalance",
216
+ "eth_getCode",
217
+ "eth_getStorageAt",
218
+ "eth_getTransactionByHash",
219
+ "eth_getTransactionCount",
220
+ "eth_getTransactionReceipt",
221
+ "net_version",
222
+ "wallet_getCapabilities",
223
+ "wallet_getCallsStatus",
224
+ // Write / sign
225
+ "eth_requestAccounts",
226
+ "eth_sendTransaction",
227
+ "eth_sendRawTransaction",
228
+ "eth_sign",
229
+ "personal_sign",
230
+ "eth_signTypedData",
231
+ "eth_signTypedData_v3",
232
+ "eth_signTypedData_v4",
233
+ "wallet_addEthereumChain",
234
+ "wallet_switchEthereumChain",
235
+ "wallet_sendCalls",
236
+ "wallet_watchAsset"
237
+ ]);
238
+ var FORWARDED_PROVIDER_EVENTS = [
239
+ "accountsChanged",
240
+ "chainChanged",
241
+ "connect",
242
+ "disconnect",
243
+ "message"
244
+ ];
245
+ function parseBridgeMessage(data) {
246
+ if (!data || typeof data !== "object") return null;
247
+ const msg = data;
248
+ if (msg.protocolVersion !== BRIDGE_PROTOCOL_VERSION) return null;
249
+ switch (msg.type) {
250
+ case "blink:bridge-hello":
251
+ return msg;
252
+ case "blink:wallets-advertised":
253
+ return Array.isArray(msg.wallets) ? msg : null;
254
+ case "blink:rpc-request":
255
+ if (typeof msg.uuid !== "string" || typeof msg.id !== "string" || typeof msg.method !== "string") {
256
+ return null;
257
+ }
258
+ return msg;
259
+ case "blink:rpc-response":
260
+ if (typeof msg.id !== "string") return null;
261
+ return msg;
262
+ case "blink:rpc-event":
263
+ if (typeof msg.uuid !== "string" || typeof msg.event !== "string" || !Array.isArray(msg.args)) {
264
+ return null;
265
+ }
266
+ return msg;
267
+ case "blink:resolve-by-flag":
268
+ if (typeof msg.id !== "string" || !Array.isArray(msg.flags)) return null;
269
+ if (!msg.flags.every((f) => typeof f === "string" && f.length > 0)) return null;
270
+ return msg;
271
+ case "blink:resolve-by-flag-response":
272
+ if (typeof msg.id !== "string") return null;
273
+ if (msg.match !== null && (typeof msg.match !== "object" || !msg.match)) return null;
274
+ return msg;
275
+ default:
276
+ return null;
277
+ }
278
+ }
279
+
280
+ // src/walletBridge/rpcHost.ts
281
+ function attachRpcHost(options) {
282
+ const { iframeWindow, iframeOrigin, discoverer } = options;
283
+ const log = options.log ?? noopLog;
284
+ if (typeof window === "undefined") {
285
+ return { detach: () => {
286
+ } };
287
+ }
288
+ let detached = false;
289
+ const subscriptions = /* @__PURE__ */ new Map();
290
+ const unsubscribeFromDiscoverer = discoverer.subscribe((snapshot) => {
291
+ if (detached) return;
292
+ advertiseWallets(snapshot);
293
+ });
294
+ function postToIframe(message) {
295
+ if (detached) return;
296
+ try {
297
+ iframeWindow.postMessage(message, iframeOrigin);
298
+ } catch (err) {
299
+ log("postMessage to iframe failed", {
300
+ error: err instanceof Error ? err.message : String(err)
301
+ });
302
+ }
303
+ }
304
+ function advertiseWallets(snapshot) {
305
+ const wallets = snapshot.map((entry) => ({
306
+ uuid: entry.info.uuid,
307
+ rdns: entry.info.rdns,
308
+ name: entry.info.name,
309
+ icon: entry.info.icon
310
+ }));
311
+ console.info("[blink-bridge:parent] advertising wallets", wallets.map((w) => ({
312
+ rdns: w.rdns,
313
+ name: w.name
314
+ })));
315
+ const message = {
316
+ type: "blink:wallets-advertised",
317
+ protocolVersion: BRIDGE_PROTOCOL_VERSION,
318
+ wallets
319
+ };
320
+ postToIframe(message);
321
+ }
322
+ function ensureSubscription(uuid, provider) {
323
+ if (subscriptions.has(uuid)) return;
324
+ if (typeof provider.on !== "function") {
325
+ subscriptions.set(uuid, { provider, listeners: /* @__PURE__ */ new Map() });
326
+ return;
327
+ }
328
+ const record = { provider, listeners: /* @__PURE__ */ new Map() };
329
+ for (const event of FORWARDED_PROVIDER_EVENTS) {
330
+ const listener = (...args) => {
331
+ const eventMessage = {
332
+ type: "blink:rpc-event",
333
+ protocolVersion: BRIDGE_PROTOCOL_VERSION,
334
+ uuid,
335
+ event,
336
+ args
337
+ };
338
+ postToIframe(eventMessage);
339
+ };
340
+ try {
341
+ provider.on(event, listener);
342
+ record.listeners.set(event, listener);
343
+ } catch (err) {
344
+ log(`provider.on('${event}') threw \u2014 skipping that event`, {
345
+ uuid,
346
+ error: err instanceof Error ? err.message : String(err)
347
+ });
348
+ }
349
+ }
350
+ subscriptions.set(uuid, record);
351
+ }
352
+ function unsubscribeAll() {
353
+ for (const [, record] of subscriptions) {
354
+ const provider = record.provider;
355
+ if (typeof provider.removeListener !== "function") continue;
356
+ for (const [event, listener] of record.listeners) {
357
+ try {
358
+ provider.removeListener(event, listener);
359
+ } catch {
360
+ }
361
+ }
362
+ }
363
+ subscriptions.clear();
364
+ }
365
+ function sendError(id, code, message, data) {
366
+ const response = {
367
+ type: "blink:rpc-response",
368
+ protocolVersion: BRIDGE_PROTOCOL_VERSION,
369
+ id,
370
+ error: data === void 0 ? { code, message } : { code, message, data }
371
+ };
372
+ postToIframe(response);
373
+ }
374
+ function sendResult(id, result) {
375
+ const response = {
376
+ type: "blink:rpc-response",
377
+ protocolVersion: BRIDGE_PROTOCOL_VERSION,
378
+ id,
379
+ result
380
+ };
381
+ postToIframe(response);
382
+ }
383
+ const onMessage = (event) => {
384
+ if (detached) return;
385
+ if (event.source !== iframeWindow) return;
386
+ if (event.origin !== iframeOrigin) return;
387
+ const message = parseBridgeMessage(event.data);
388
+ if (!message) return;
389
+ switch (message.type) {
390
+ case "blink:bridge-hello": {
391
+ advertiseWallets(discoverer.list());
392
+ discoverer.requestProviders();
393
+ return;
394
+ }
395
+ case "blink:rpc-request": {
396
+ const { id, uuid, method, params } = message;
397
+ console.info("[blink-bridge:parent] rpc-request", { uuid, method });
398
+ if (!ALLOWED_RPC_METHODS.has(method)) {
399
+ log("rejecting non-allowlisted method", { uuid, method });
400
+ sendError(id, -32601, `Method not allowed: ${method}`);
401
+ return;
402
+ }
403
+ const provider = discoverer.get(uuid);
404
+ if (!provider) {
405
+ log("no provider for uuid", { uuid, method });
406
+ sendError(id, -32602, `Unknown wallet: ${uuid}`);
407
+ return;
408
+ }
409
+ ensureSubscription(uuid, provider);
410
+ provider.request({ method, params }).then((result) => {
411
+ console.info("[blink-bridge:parent] rpc-result", { uuid, method, ok: true });
412
+ sendResult(id, result);
413
+ }).catch((err) => {
414
+ const { code, message: errMessage, data } = normalizeProviderError(err);
415
+ console.info("[blink-bridge:parent] rpc-error", { uuid, method, code, message: errMessage });
416
+ sendError(id, code, errMessage, data);
417
+ });
418
+ return;
419
+ }
420
+ case "blink:resolve-by-flag": {
421
+ const match = resolveByFlag(discoverer.list(), message.flags, log);
422
+ console.info("[blink-bridge:parent] resolveByFlag", {
423
+ flags: message.flags,
424
+ match: match ? { rdns: match.rdns, flag: match.flag } : null
425
+ });
426
+ const response = {
427
+ type: "blink:resolve-by-flag-response",
428
+ protocolVersion: BRIDGE_PROTOCOL_VERSION,
429
+ id: message.id,
430
+ match
431
+ };
432
+ postToIframe(response);
433
+ return;
434
+ }
435
+ case "blink:wallets-advertised":
436
+ case "blink:rpc-response":
437
+ case "blink:rpc-event":
438
+ case "blink:resolve-by-flag-response":
439
+ return;
440
+ }
441
+ };
442
+ window.addEventListener("message", onMessage);
443
+ return {
444
+ detach() {
445
+ if (detached) return;
446
+ detached = true;
447
+ window.removeEventListener("message", onMessage);
448
+ unsubscribeFromDiscoverer();
449
+ unsubscribeAll();
450
+ }
451
+ };
452
+ }
453
+ function noopLog() {
454
+ }
455
+ function resolveByFlag(snapshot, flags, log) {
456
+ for (const flag of flags) {
457
+ for (const entry of snapshot) {
458
+ let value;
459
+ try {
460
+ value = entry.provider[flag];
461
+ } catch (err) {
462
+ log("provider threw on flag read \u2014 skipping", {
463
+ rdns: entry.info.rdns,
464
+ flag,
465
+ error: err instanceof Error ? err.message : String(err)
466
+ });
467
+ continue;
468
+ }
469
+ if (value) {
470
+ return { rdns: entry.info.rdns, uuid: entry.info.uuid, flag };
471
+ }
472
+ }
473
+ }
474
+ return null;
475
+ }
476
+ function normalizeProviderError(err) {
477
+ if (err && typeof err === "object") {
478
+ const e = err;
479
+ const code = typeof e.code === "number" ? e.code : -32603;
480
+ const message = typeof e.message === "string" ? e.message : err instanceof Error ? err.message : "Provider error";
481
+ const data = "data" in e ? e.data : void 0;
482
+ return data === void 0 ? { code, message } : { code, message, data };
483
+ }
484
+ return { code: -32603, message: typeof err === "string" ? err : "Provider error" };
485
+ }
486
+
97
487
  // src/iframe.ts
98
488
  var STYLE_ID = "blink-deposit-styles";
99
489
  var CLOSE_DURATION_MS = 280;
@@ -129,13 +519,26 @@ function createIframe(url, containerElement) {
129
519
  const iframe = document.createElement("iframe");
130
520
  iframe.src = url;
131
521
  const iframeOrigin = new URL(url).origin;
132
- iframe.allow = `publickey-credentials-get ${iframeOrigin}; publickey-credentials-create ${iframeOrigin}`;
522
+ iframe.allow = `publickey-credentials-get ${iframeOrigin}; publickey-credentials-create ${iframeOrigin}; clipboard-write ${iframeOrigin}`;
133
523
  const handle = document.createElement("div");
134
524
  container.appendChild(handle);
135
525
  container.appendChild(iframe);
136
526
  overlay.appendChild(container);
137
527
  const mountTarget = containerElement ?? document.body;
138
528
  mountTarget.appendChild(overlay);
529
+ const discoverer = createWalletDiscoverer();
530
+ let rpcHostHandle = null;
531
+ const attachBridge = () => {
532
+ if (rpcHostHandle) return;
533
+ if (!iframe.contentWindow) return;
534
+ rpcHostHandle = attachRpcHost({
535
+ iframeWindow: iframe.contentWindow,
536
+ iframeOrigin,
537
+ discoverer
538
+ });
539
+ };
540
+ attachBridge();
541
+ iframe.addEventListener("load", attachBridge);
139
542
  const savedOverflow = document.body.style.overflow;
140
543
  document.body.style.overflow = "hidden";
141
544
  const onBackdropClick = (event) => {
@@ -162,6 +565,7 @@ function createIframe(url, containerElement) {
162
565
  if (closed) return;
163
566
  closed = true;
164
567
  removeListeners();
568
+ detachBridge();
165
569
  overlay.setAttribute("data-blink-closing", "");
166
570
  let removed = false;
167
571
  const removeOverlay = () => {
@@ -174,6 +578,14 @@ function createIframe(url, containerElement) {
174
578
  container.addEventListener("animationend", removeOverlay, { once: true });
175
579
  setTimeout(removeOverlay, CLOSE_DURATION_MS + 50);
176
580
  }
581
+ function detachBridge() {
582
+ iframe.removeEventListener("load", attachBridge);
583
+ if (rpcHostHandle) {
584
+ rpcHostHandle.detach();
585
+ rpcHostHandle = null;
586
+ }
587
+ discoverer.destroy();
588
+ }
177
589
  return {
178
590
  get contentWindow() {
179
591
  return iframe.contentWindow;
@@ -192,6 +604,7 @@ function createIframe(url, containerElement) {
192
604
  if (!closed) {
193
605
  closed = true;
194
606
  removeListeners();
607
+ detachBridge();
195
608
  overlay.remove();
196
609
  unlockScroll();
197
610
  }
@@ -314,8 +727,10 @@ function isValidTokenAddress(value) {
314
727
  return TOKEN_ADDRESS_RE.test(value) || SOLANA_ADDRESS_RE.test(value);
315
728
  }
316
729
  function validateDepositRequest(request) {
317
- if (!Number.isFinite(request.amount) || request.amount <= 0) {
318
- throw new DepositError("INVALID_REQUEST", "amount must be a positive number.");
730
+ if (request.amount !== null) {
731
+ if (typeof request.amount !== "number" || !Number.isFinite(request.amount) || request.amount <= 0) {
732
+ throw new DepositError("INVALID_REQUEST", "amount must be a positive number or null.");
733
+ }
319
734
  }
320
735
  if (!Number.isInteger(request.chainId) || request.chainId <= 0) {
321
736
  throw new DepositError("INVALID_REQUEST", "chainId must be a positive integer.");