@enbox/browser 0.3.52 → 0.3.54

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../src/web-features.ts", "../src/drl-url-parser.ts", "../src/ui/connect-modal.ts", "../src/ui/wallet-icon.ts", "../src/dweb-connect-client.ts", "../src/dweb-connect-messages.ts", "../src/ui/qr.ts", "../src/ui/wallet-well-known.ts", "../src/relay-connect-runner.ts", "../src/browser-connect-handler.ts", "../src/dweb-connect-wallet.ts"],
4
- "sourcesContent": ["/**\n * @enbox/browser \u2014 The Enbox browser SDK.\n *\n * For browser-based dapps, this is the only package you need to import.\n * It re-exports the high-level API from `@enbox/api`, the authentication\n * layer from `@enbox/auth`, and provides browser-specific connect handlers.\n *\n * @example Single-import dapp setup\n * ```ts\n * import {\n * Enbox, BrowserConnectHandler,\n * defineProtocol, repository,\n * } from '@enbox/browser';\n *\n * const { enbox, session } = await Enbox.connect({\n * connectHandler: BrowserConnectHandler({ appName: 'My App' }),\n * protocols: [MyProtocol],\n * });\n * ```\n *\n * For non-browser environments (Node.js, CLI, desktop), import from\n * `@enbox/api` and `@enbox/auth` directly instead.\n *\n * @packageDocumentation\n */\n\n// \u2500\u2500\u2500 Re-exports from @enbox/api \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The high-level Enbox API: DWN records, protocols, repositories.\n\nexport {\n Enbox,\n defineProtocol,\n repository,\n} from '@enbox/api';\n\nexport type {\n EnboxAnonymousOptions,\n EnboxConnectOptions,\n EnboxConnectResult,\n EnboxParams,\n EnboxSessionParams,\n} from '@enbox/api';\n\n// \u2500\u2500\u2500 Re-exports from @enbox/auth \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Authentication lifecycle, session management, connect handlers.\n\nexport {\n AuthManager,\n AuthSession,\n normalizeProtocolRequests,\n WalletConnect,\n} from '@enbox/auth/browser';\n\nexport type {\n AuthEvent,\n AuthEventHandler,\n AuthManagerOptions,\n AuthState,\n ConnectHandler,\n ConnectOptions,\n ConnectResult,\n DisconnectOptions,\n HandlerConnectOptions,\n ImportFromPortableOptions,\n VaultConnectOptions,\n Permission,\n PortableIdentity,\n ProtocolRequest,\n RegistrationOptions,\n StorageAdapter,\n SyncOption,\n WalletConnectOptions,\n} from '@enbox/auth/browser';\n\n// \u2500\u2500\u2500 Re-exports from @enbox/connect \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The connect kernel pieces wallet apps need alongside the popup\n// transports: opening/sealing envelopes and the deny token.\n\nexport { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';\nexport type { ConnectApproval, ConnectPermissionRequest, ConnectRequest } from '@enbox/connect';\n\n// \u2500\u2500\u2500 Browser-specific exports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// DWeb Connect popup transports, wallet selector, DRL polyfills.\n\nexport * from './web-features.js';\nexport { BrowserConnectHandler, DEFAULT_WALLETS } from './browser-connect-handler.js';\nexport type { BrowserConnectHandlerOptions, WalletOption } from './browser-connect-handler.js';\nexport { connectViaPopup, PopupClientTransport, PopupWindowClosedError } from './dweb-connect-client.js';\nexport type { PopupClientTransportOptions, PopupConnectOptions } from './dweb-connect-client.js';\nexport { WalletPostMessageTransport } from './dweb-connect-wallet.js';\nexport type { WalletPostMessageTransportOptions } from './dweb-connect-wallet.js';\nexport {\n DWEB_CONNECT_ACK_MESSAGE_TYPE,\n DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n DWEB_CONNECT_PATH,\n DWEB_CONNECT_REQUEST_MESSAGE_TYPE,\n DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n} from './dweb-connect-messages.js';\nexport type {\n DWebConnectAckMessage,\n DWebConnectLoadedMessage,\n DWebConnectRequestMessage,\n DWebConnectResponseMessage,\n} from './dweb-connect-messages.js';\nexport { fetchWalletWellKnown, probeWalletWellKnown, WALLET_WELL_KNOWN_PATH } from './ui/wallet-well-known.js';\nexport type { WalletWellKnownDocument } from './ui/wallet-well-known.js';\nexport { discoverWalletConnectServerUrl, runConnectModal } from './ui/connect-modal.js';\nexport type { ConnectMethod, ConnectModalDeps, ConnectModalOptions, ConnectModalPalette, ConnectModalTheme } from './ui/connect-modal.js';\nexport { MAX_PIN_ATTEMPTS, RelayConnectCancelledError, runRelayConnect } from './relay-connect-runner.js';\nexport type { RelayConnectOptions } from './relay-connect-runner.js';\nexport { encodeQr, qrToSvg } from './ui/qr.js';\nexport type { QrCode, QrSvgOptions } from './ui/qr.js';\n\n// \u2500\u2500\u2500 Convenience re-exports for dapps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// So that most browser dapps only need `@enbox/browser` (plus\n// `@enbox/protocols` for shared protocol definitions). These surface the\n// symbols dapps most commonly reached into sibling packages for; anything\n// more specialized is still available by importing the underlying package\n// directly.\n\n// Typed record wrapper (from @enbox/api).\nexport { TypedRecord } from '@enbox/api';\n\n// Custom storage adapter + DWN registration provider-auth callback shapes\n// (from @enbox/auth).\nexport { BrowserStorage } from '@enbox/auth/browser';\nexport type { ProviderAuthParams, ProviderAuthResult } from '@enbox/auth/browser';\n\n// DWN interface enum for typing agent requests (from @enbox/agent).\nexport { DwnInterface } from '@enbox/agent';\n\n// Common DWN primitives for record queries, permission scopes, and protocol\n// typing (from @enbox/dwn-sdk-js).\nexport { DateSort, DwnInterfaceName, DwnMethodName } from '@enbox/dwn-sdk-js';\nexport type { ProtocolActionRule, ProtocolDefinition } from '@enbox/dwn-sdk-js';\n", "/*\n This file is run in dual environments to make installation of the Service Worker code easier.\n Be mindful that code placed in any open excution space may be evaluated multiple times in different contexts,\n so take care to gate additions to only activate code in the right env, such as a Service Worker scope or page window.\n*/\n\nimport type { DidMethodResolver } from '@enbox/dids';\n\nimport { DidDht, DidWeb, UniversalResolver } from '@enbox/dids';\n\n/**\n * Result returned by the `onCacheCheck` callback.\n * When returned, it signals that the response for the given DRL should be cached.\n */\nexport type CacheCheckResult = {\n /** Time-to-live for the cached DRL response, in milliseconds. */\n ttl?: number;\n};\n\n/**\n * Callback invoked to determine whether a DRL response should be cached and for how long.\n * Returning a truthy `CacheCheckResult` opts in to caching; returning a falsy value skips it.\n */\nexport type CacheCheckCallback = (\n event: FetchEvent | Event,\n drl: string,\n) => CacheCheckResult | undefined | null | Promise<CacheCheckResult | undefined | null>;\n\n/**\n * Configuration options for {@link activatePolyfills}.\n */\nexport type ActivatePolyfillsOptions = {\n /**\n * Path to the script to register as a Service Worker.\n * Falls back to `document.currentScript.src` or `import.meta.url`.\n *\n * **Required in strict CSP environments** where `new Function()` is blocked and `import.meta`\n * cannot be evaluated dynamically.\n */\n path?: string;\n /** Set to `false` to skip Service Worker installation. Defaults to `true`. */\n serviceWorker?: boolean;\n /** Set to `false` to skip injection of DRL loading-overlay styles. Defaults to `true`. */\n injectStyles?: boolean;\n /** Set to `false` to skip activation of DRL anchor/link click handling. Defaults to `true`. */\n links?: boolean;\n /** Callback to control per-request caching behaviour. */\n onCacheCheck?: CacheCheckCallback;\n /**\n * DID method resolvers to use for DRL resolution. Defaults to `[DidDht, DidWeb]`.\n * Pass a custom array to add or replace DID methods (e.g., `[DidDht, DidWeb, DidJwk]`).\n */\n didResolvers?: DidMethodResolver[];\n};\n\n/**\n * An `HTMLElement` that has a `src` property (e.g., `<img>`, `<video>`, `<audio>`).\n * Extended with `__src__` to stash the original DRL src during context-menu swaps.\n */\ninterface DrlMediaElement extends HTMLElement {\n src: string;\n __src__?: string;\n}\n\nlet didResolver = new UniversalResolver({ didResolvers: [DidDht, DidWeb] });\n\nimport { parseDrlUrl } from './drl-url-parser.js';\nexport { parseDrlUrl } from './drl-url-parser.js';\n\nconst httpToHttpsRegex = /^http:/;\nconst trailingSlashRegex = /\\/$/;\nconst DRL_CACHE_NAME = 'drl';\n\n/** @internal Exported for testing. Resolves DWN service endpoints from a DID. */\nexport async function getDwnEndpoints(did: string): Promise<string[]> {\n const { didDocument } = await didResolver.resolve(did);\n const endpoints = didDocument?.service?.find(\n (service) => service.type === 'DecentralizedWebNode'\n )?.serviceEndpoint;\n if (!endpoints) {return [];}\n return (Array.isArray(endpoints) ? endpoints : [endpoints]).filter(\n (url) => typeof url === 'string' && url.startsWith('http')\n );\n}\n\n/** Returns an open DRL cache, or `undefined` if the Cache API is unavailable. */\nasync function openDrlCache(): Promise<Cache | undefined> {\n if (typeof caches === 'undefined') {return undefined;}\n return caches.open(DRL_CACHE_NAME);\n}\n\n/** @internal Exported for testing. Handles a DRL fetch event. */\nexport async function handleEvent(\n event: FetchEvent, did: string, path: string, options?: ActivatePolyfillsOptions\n): Promise<Response> {\n const drl = event.request.url\n .replace(httpToHttpsRegex, 'https:')\n .replace(trailingSlashRegex, '');\n const responseCache = await openDrlCache();\n const cachedResponse = await responseCache?.match(drl);\n if (cachedResponse) {\n if (!navigator.onLine) {return cachedResponse;}\n const match = await options?.onCacheCheck?.(event, drl);\n if (match) {\n const cacheTime = cachedResponse.headers.get('dwn-cache-time');\n if (\n cacheTime &&\n Date.now() < Number(cacheTime) + (Number(match.ttl) || 0)\n ) {\n return cachedResponse;\n }\n }\n }\n try {\n if (path) {\n return await fetchResource(event, did, drl, path, responseCache, options);\n } else {\n const response = await didResolver.resolve(did);\n return new Response(JSON.stringify(response), {\n status : 200,\n headers : {\n 'Content-Type': 'application/json',\n },\n });\n }\n } catch (error) {\n if (error instanceof Response) {\n return error;\n }\n console.log(`Error in DID URL fetch: ${error}`);\n return new Response('DID URL fetch error', { status: 500 });\n }\n}\n\n/** @internal Exported for testing. Fetches a resource from DWN endpoints. */\nexport async function fetchResource(\n event: FetchEvent, did: string, drl: string, path: string,\n responseCache: Cache | undefined, options?: ActivatePolyfillsOptions\n): Promise<Response> {\n const endpoints = await getDwnEndpoints(did);\n if (!endpoints?.length) {\n throw new Response(\n 'DWeb Node resolution failed: no valid endpoints found.',\n { status: 530 }\n );\n }\n let lastError: Response | undefined;\n for (const endpoint of endpoints) {\n try {\n const url = `${endpoint.replace(trailingSlashRegex, '')}/${did}/${path}`;\n const response = await fetch(url, { headers: event.request.headers });\n if (response.ok) {\n const match = await options?.onCacheCheck?.(event, drl);\n if (match && responseCache) {\n cacheResponse(drl, url, response, responseCache);\n }\n return response;\n }\n console.log(`DWN endpoint error: ${response.status}`);\n lastError = new Response('DWeb Node request failed', {\n status: response.status,\n });\n } catch (error) {\n console.log(`DWN endpoint error: ${error}`);\n lastError = new Response('DWeb Node request failed', {\n status: 500,\n });\n }\n }\n return lastError!;\n}\n\n/** @internal Exported for testing. Caches a DRL response with metadata headers. */\nexport async function cacheResponse(drl: string, url: string, response: Response, cache: Cache): Promise<void> {\n try {\n const clonedResponse = response.clone();\n const headers = new Headers(clonedResponse.headers);\n headers.append('dwn-cache-time', Date.now().toString());\n headers.append('dwn-composed-url', url);\n const modifiedResponse = new Response(clonedResponse.body, { headers });\n await cache.put(drl, modifiedResponse);\n } catch (error) {\n console.log(`Failed to cache DRL response: ${error}`);\n }\n}\n\n/* Service Worker-based features */\n\nasync function installWorker(options: ActivatePolyfillsOptions = {}): Promise<void> {\n try {\n // Check to see if we are in a Service Worker already, if so, proceed\n // You can call the activatePolyfills() function in your own worker, or standalone as a root worker\n if (\n typeof ServiceWorkerGlobalScope !== 'undefined' &&\n self instanceof ServiceWorkerGlobalScope\n ) {\n const workerSelf = self as unknown as ServiceWorkerGlobalScope;\n workerSelf.skipWaiting();\n workerSelf.addEventListener('activate', (event: ExtendableEvent) => {\n // Claim clients to make the service worker take control immediately\n event.waitUntil(workerSelf.clients.claim());\n });\n workerSelf.addEventListener('fetch', (event: FetchEvent) => {\n const parsed = parseDrlUrl(event.request.url);\n if (parsed) {\n event.respondWith(handleEvent(event, parsed[0], parsed[1], options));\n }\n });\n }\n // If the code gets here, it is not a SW env, it is likely DOM, but check to be sure\n else if (globalThis?.navigator?.serviceWorker) {\n const registration = await navigator.serviceWorker.getRegistration('/');\n // You can only have one worker per path, so check to see if one is already registered\n if (!registration) {\n const installUrl: string | undefined =\n options.path ||\n (document?.currentScript as HTMLScriptElement | null)?.src ||\n import.meta.url;\n if (installUrl)\n {navigator.serviceWorker\n .register(installUrl, { type: 'module' })\n .catch((error: unknown) => {\n console.error(\n 'DWeb networking feature installation failed: ',\n error\n );\n });}\n }\n } else {\n throw new Error(\n 'DWeb networking features are not available for install in this environment'\n );\n }\n } catch (error) {\n console.error('Error in installing networking features:', error);\n }\n}\n\n/* DOM Environment Features */\n\nconst loaderStyles = `\n .drl-loading-overlay {\n position: fixed;\n inset: 0;\n display: flex;\n flex-wrap: wrap;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n color: #fff;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(15px);\n -webkit-backdrop-filter: blur(15px);\n z-index: 1000000;\n }\n\n .drl-loading-overlay > div {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .drl-loading-spinner {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .drl-loading-spinner div {\n position: relative;\n width: 2em;\n height: 2em;\n margin: 0.1em 0.25em 0 0;\n }\n .drl-loading-spinner div::after,\n .drl-loading-spinner div::before {\n content: ''; \n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 0.1em solid #FFF;\n position: absolute;\n left: 0;\n top: 0;\n opacity: 0;\n animation: drl-loading-spinner 2s linear infinite;\n }\n .drl-loading-spinner div::after {\n animation-delay: 1s;\n }\n\n .drl-loading-overlay span {\n --text-opacity: 2;\n display: flex;\n align-items: center;\n margin: 2em auto 0;\n padding: 0.2em 0.75em 0.25em;\n text-align: center;\n border-radius: 5em;\n background: rgba(255 255 255 / 8%);\n opacity: 0.8;\n transition: opacity 0.3s ease;\n cursor: pointer;\n }\n\n .drl-loading-overlay span:focus {\n opacity: 1;\n }\n\n .drl-loading-overlay span:hover {\n opacity: 1;\n }\n\n .drl-loading-overlay span::before {\n content: '\u2715 ';\n margin: 0 0.4em 0 0;\n color: red;\n font-size: 65%;\n font-weight: bold;\n }\n\n .drl-loading-overlay span::after {\n content: 'stop';\n display: block;\n font-size: 60%;\n line-height: 0;\n color: rgba(255 255 255 / 60%);\n }\n\n .drl-loading-overlay.new-tab-overlay span::after {\n content: 'close';\n }\n \n @keyframes drl-loading-spinner {\n 0% {\n transform: scale(0);\n opacity: 1;\n }\n 100% {\n transform: scale(1);\n opacity: 0;\n }\n }\n`;\nconst tabContent = `\n<!DOCTYPE html>\n<html lang='en'>\n<head>\n <meta charset='UTF-8'>\n <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n <title>Loading DRL...</title>\n <style>\n html, body {\n background-color: #151518;\n height: 100%;\n margin: 0;\n padding: 0;\n font-family: Arial, sans-serif;\n text-align: center;\n }\n ${loaderStyles}\n </style>\n</head>\n<body>\n <div class='drl-loading-overlay new-tab-overlay'>\n <div class='drl-loading-spinner'>\n <div></div>\n Loading DRL\n </div>\n <span onclick='window.close()' tabindex='0'></span>\n </div>\n</body>\n</html>\n`;\n\nlet elementsInjected = false;\nlet overlayElement: HTMLDivElement | null = null;\nlet styleElement: HTMLStyleElement | null = null;\n\nfunction injectElements(): void {\n if (elementsInjected) {return;}\n styleElement = document.createElement('style');\n styleElement.innerHTML = `\n ${loaderStyles}\n\n .drl-loading-overlay {\n opacity: 0;\n transition: opacity 0.3s ease;\n pointer-events: none;\n }\n\n :root[drl-link-loading] .drl-loading-overlay {\n opacity: 1;\n pointer-events: all;\n }\n `;\n document.head.append(styleElement);\n\n overlayElement = document.createElement('div');\n overlayElement.classList.add('drl-loading-overlay');\n overlayElement.innerHTML = `\n <div class='drl-loading-spinner'>\n <div></div>\n Loading DRL\n </div> \n <span tabindex='0'></span>\n `;\n overlayElement.lastElementChild!.addEventListener('click', cancelNavigation);\n document.body.prepend(overlayElement);\n elementsInjected = true;\n}\n\nfunction removeElements(): void {\n if (!elementsInjected) {return;}\n styleElement?.remove();\n styleElement = null;\n overlayElement?.remove();\n overlayElement = null;\n elementsInjected = false;\n}\n\nfunction cancelNavigation(): void {\n document.documentElement.removeAttribute('drl-link-loading');\n activeNavigation = null;\n}\n\nlet activeNavigation: string | null = null;\nlet linkFeaturesActive = false;\n\n// Stored references for listener cleanup in deactivatePolyfills()\nlet clickHandler: ((event: MouseEvent) => Promise<void>) | null = null;\nlet pointerdownHandler: ((event: PointerEvent) => Promise<void>) | null = null;\n\nfunction addLinkFeatures(): void {\n if (!linkFeaturesActive) {\n clickHandler = async (event: MouseEvent): Promise<void> => {\n const anchor = (event.target as Element)?.closest('a');\n if (anchor) {\n const href = anchor.href;\n const parsed = parseDrlUrl(href);\n if (parsed) {\n const did = parsed[0];\n const path = parsed[1];\n const openAsTab = anchor.target === '_blank';\n event.preventDefault();\n try {\n let tab: Window | null = null;\n if (openAsTab) {\n tab = window.open('', '_blank');\n if (tab) {tab.document.write(tabContent);}\n } else {\n activeNavigation = path;\n // this is to allow for cached DIDs to instantly load without any flash of loading UI\n setTimeout(\n () =>\n document.documentElement.setAttribute('drl-link-loading', ''),\n 50\n );\n }\n const endpoints = await getDwnEndpoints(did);\n if (!endpoints.length) {\n throw new Error('no valid DWN endpoints found');\n }\n const url = `${endpoints[0].replace(\n trailingSlashRegex,\n ''\n )}/${did}/${path}`;\n if (openAsTab) {\n if (tab && !tab.closed) {tab.location.href = url;}\n } else if (activeNavigation === path) {\n window.location.href = url;\n }\n } catch {\n if (activeNavigation === path) {\n cancelNavigation();\n }\n throw new Error(\n `DID endpoint resolution failed for the DRL: ${href}`\n );\n }\n }\n }\n };\n\n pointerdownHandler = async (event: PointerEvent): Promise<void> => {\n const target = event.composedPath()[0] as DrlMediaElement | undefined;\n if (\n (event.pointerType === 'mouse' && event.button === 2) ||\n (event.pointerType === 'touch' && event.isPrimary)\n ) {\n resetContextMenuTarget();\n if (target?.src && parseDrlUrl(target.src)) {\n contextMenuTarget = target;\n target.__src__ = target.src;\n const drl = target.src\n .replace(httpToHttpsRegex, 'https:')\n .replace(trailingSlashRegex, '');\n const responseCache = await openDrlCache();\n const response = await responseCache?.match(drl);\n if (response) {\n const url = response.headers.get('dwn-composed-url');\n if (url) {target.src = url;}\n }\n target.addEventListener('pointerup', resetContextMenuTarget, {\n once: true,\n });\n }\n } else if (target === contextMenuTarget) {\n resetContextMenuTarget();\n }\n };\n\n document.addEventListener('click', clickHandler);\n document.addEventListener('pointercancel', resetContextMenuTarget);\n document.addEventListener('pointerdown', pointerdownHandler);\n\n linkFeaturesActive = true;\n }\n}\n\nfunction removeLinkFeatures(): void {\n if (!linkFeaturesActive) {return;}\n if (clickHandler) {\n document.removeEventListener('click', clickHandler);\n clickHandler = null;\n }\n if (pointerdownHandler) {\n document.removeEventListener('pointerdown', pointerdownHandler);\n pointerdownHandler = null;\n }\n document.removeEventListener('pointercancel', resetContextMenuTarget);\n resetContextMenuTarget();\n cancelNavigation();\n linkFeaturesActive = false;\n}\n\nlet contextMenuTarget: DrlMediaElement | null = null;\nasync function resetContextMenuTarget(e?: Event): Promise<void> {\n if (e?.type === 'pointerup') {\n await new Promise<void>((r) => requestAnimationFrame(() => r()));\n }\n if (contextMenuTarget) {\n contextMenuTarget.src = contextMenuTarget.__src__!;\n delete contextMenuTarget.__src__;\n contextMenuTarget = null;\n }\n}\n\n/**\n * Activates various polyfills to enable Enbox features in Web environments.\n *\n * @param options - Configuration options to control the activation of polyfills.\n *\n * @example\n * // Activate all polyfills with default options, and cache every DRL for 1 minute\n * activatePolyfills({\n * onCacheCheck(event, route){\n * return {\n * ttl: 60_000\n * }\n * }\n * });\n *\n * @example\n * // Activate polyfills, but without Service Worker activation\n * activatePolyfills({ serviceWorker: false });\n *\n * @example\n * // Use custom DID resolvers\n * activatePolyfills({ didResolvers: [DidDht, DidWeb, DidJwk] });\n */\nexport function activatePolyfills(options: ActivatePolyfillsOptions = {}): void {\n if (options.didResolvers) {\n didResolver = new UniversalResolver({ didResolvers: options.didResolvers });\n }\n if (options.serviceWorker !== false) {\n installWorker(options);\n }\n if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {\n if (options.injectStyles !== false) {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', injectElements, {\n once: true,\n });\n } else {injectElements();}\n }\n if (options.links !== false) {addLinkFeatures();}\n }\n}\n\n/**\n * Removes all polyfill event listeners, injected DOM elements, and resets internal state.\n * Call this to fully clean up after {@link activatePolyfills}.\n *\n * Does **not** unregister an installed Service Worker \u2014 use\n * `navigator.serviceWorker.getRegistration('/').then(r => r?.unregister())` for that.\n */\nexport function deactivatePolyfills(): void {\n if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {\n removeLinkFeatures();\n removeElements();\n }\n}\n\n/**\n * Deletes the entire DRL response cache.\n * Useful for clearing stale cached DWN responses.\n *\n * @returns `true` if the cache existed and was deleted, `false` otherwise.\n * Returns `false` if the Cache API is unavailable.\n */\nexport async function clearDrlCache(): Promise<boolean> {\n if (typeof caches === 'undefined') {return false;}\n return caches.delete(DRL_CACHE_NAME);\n}\n", "/**\n * Parses a DRL URL (http(s)://dweb/{did}/{path}) without regex quantifiers.\n * Returns `[did, path]` or `null` if the URL does not match the DRL scheme.\n *\n * Extracted to a standalone module so it can be tested under Node.js (bun:test)\n * in addition to the browser-based vitest suite, ensuring SonarCloud's\n * merged coverage report includes these lines.\n */\nexport function parseDrlUrl(url: string): [string, string] | null {\n const idx = url.indexOf('://dweb/');\n if (idx === -1) { return null; }\n const prefix = url.slice(0, idx);\n if (prefix !== 'http' && prefix !== 'https') { return null; }\n const rest = url.slice(idx + 8); // '://dweb/'.length === 8\n if (rest.length === 0) { return null; }\n const slashIdx = rest.indexOf('/');\n if (slashIdx === -1) { return [rest, '']; }\n if (slashIdx === 0) { return null; } // DID segment must be non-empty\n return [rest.slice(0, slashIdx), rest.slice(slashIdx + 1)];\n}\n", "/**\n * Connect modal \u2014 the single surface that owns a whole connect session.\n *\n * One Shadow-DOM dialog whose stage morphs in place through the session:\n * QR / deep-link handoff (phone path) \u2192 pairing code \u2192 connected, with the\n * in-browser popup path and the wallet catalog folded in as in-place\n * alternates. The modal never chains into a second modal and stays mounted\n * until the session resolves (connected / denied / cancelled).\n *\n * Layout: three zones \u2014\n *\n * 1. **Header** \u2014 requesting app identity + close.\n * 2. **Stage** \u2014 a height-stable region where states crossfade: the\n * clickable QR (joined by a Continue deep-link button on phones; both\n * open the wallet in a new tab so this session stays alive underneath),\n * the pairing-code input, progress, success, and error states.\n * 3. **Footer** \u2014 the wallet identity row (\"Connecting with\" + the selected\n * wallet and the next catalog wallets as tiles), a More tile that expands\n * the remaining wallets as a matching grid (search + custom URL) in\n * place \u2014 a wallet is never shown twice \u2014 and the alternate-method link.\n *\n * Theming: the stylesheet is static and reads `--ec-*` design tokens.\n * Light/dark follows the visitor's system via `prefers-color-scheme` and\n * updates live; the embedding app can force an appearance or override\n * palette tokens through {@link ConnectModalOptions.theme}. Overrides are\n * applied as inline custom properties \u2014 never interpolated into the\n * stylesheet \u2014 so a hostile string can't escape its declaration. The QR\n * card alone is theme-invariant (dark modules on white scan most\n * reliably).\n *\n * The phone path drives the `@enbox/connect` relay transport via\n * {@link runRelayConnect}; the browser path drives the popup transport via\n * the kernel `ConnectClient`. Wallet `connectServerUrl`s are discovered\n * from each wallet's `/.well-known/enbox-connect` document unless\n * overridden.\n *\n * @module\n */\n\nimport type { WalletOption } from '../browser-connect-handler.js';\nimport type { ConnectPermissionRequest, ConnectResult, WalletUriHandoff } from '@enbox/connect';\n\nimport { ConnectClient } from '@enbox/connect';\n\nimport { buildWalletIcon } from './wallet-icon.js';\nimport {\n collectBrowserClientMetadata,\n PopupClientTransport,\n PopupWindowClosedError,\n} from '../dweb-connect-client.js';\nimport { encodeQr, qrToSvg } from './qr.js';\nimport { fetchWalletWellKnown, probeWalletWellKnown } from './wallet-well-known.js';\nimport { RelayConnectCancelledError, runRelayConnect } from '../relay-connect-runner.js';\n\n/** How the user carries out the approval. */\nexport type ConnectMethod = 'phone' | 'browser';\n\n/** localStorage key remembering the last successful method + wallet. */\nconst LAST_CHOICE_STORAGE_KEY = 'enbox:connect:lastChoice';\n\n/**\n * Safety margin subtracted from the relay pointer TTL before re-minting.\n *\n * The pointer is single-use and its TTL starts at mint time, but the wallet\n * only dereferences it after the user scans \u2014 and, on a locked wallet, after\n * they finish the unlock ceremony. A scanned code must therefore carry\n * enough remaining life to absorb that whole window, so re-mint well before\n * the deadline rather than just ahead of it.\n */\nconst REMINT_SAFETY_MS = 120_000;\n\n/** Minimum delay before an automatic re-mint. */\nconst REMINT_MIN_MS = 10_000;\n\n/** Pairing code length (matches the wallet's generated PIN). */\nconst PIN_LENGTH = 4;\n\n/** Catalog size beyond which the wallet switcher shows its search bar. */\nconst WALLET_SEARCH_THRESHOLD = 4; // one full row of tiles\n\n/** Wallet tiles shown in the collapsed identity row (plus the More tile). */\nconst WALLET_ROW_SIZE = 3;\n\n/** Palette overrides for one appearance's design tokens. */\nexport interface ConnectModalPalette {\n /** Modal surface. */\n background?: string;\n\n /** Inset surfaces: tiles, inputs, hover fills. */\n surface?: string;\n\n /** Primary text. */\n text?: string;\n\n /** Secondary text. */\n textMuted?: string;\n\n /** Hairline borders and dividers. */\n border?: string;\n\n /** Brand accent: buttons, links, focus rings, selection. */\n accent?: string;\n\n /** Text/icon color on accent surfaces. */\n accentContrast?: string;\n\n /** Error text and invalid-input borders. */\n danger?: string;\n\n /** Success surfaces (the connected check). */\n success?: string;\n}\n\n/** Optional color scheme provided by the embedding app. */\nexport interface ConnectModalTheme {\n /**\n * Follow the visitor's system appearance (`'auto'`, live-updating) or\n * force one.\n * @default 'auto'\n */\n appearance?: 'auto' | 'light' | 'dark';\n\n /** Brand accent applied in both appearances (per-scheme palettes win). */\n accent?: string;\n\n /** Text/icon color on accent surfaces, in both appearances. */\n accentContrast?: string;\n\n /** Token overrides applied while the light appearance is active. */\n light?: ConnectModalPalette;\n\n /** Token overrides applied while the dark appearance is active. */\n dark?: ConnectModalPalette;\n}\n\n/** Design-token custom property behind each palette key. */\nconst PALETTE_TOKENS: Record<keyof ConnectModalPalette, string> = {\n background : '--ec-bg',\n surface : '--ec-surface',\n text : '--ec-text',\n textMuted : '--ec-muted',\n border : '--ec-border',\n accent : '--ec-accent',\n accentContrast : '--ec-accent-contrast',\n danger : '--ec-danger',\n success : '--ec-success',\n};\n\n/** Options for {@link runConnectModal}. */\nexport interface ConnectModalOptions {\n /** Wallet catalog shown in the wallet switcher. */\n wallets?: WalletOption[];\n\n /**\n * Explicit wallet URL: hides the catalog switcher and uses this wallet\n * for both methods.\n */\n walletUrl?: string;\n\n /** Preferred method on open; overrides the remembered choice. */\n preferredMethod?: ConnectMethod;\n\n /**\n * Remember the successful method + wallet in localStorage and pre-shape\n * the next session accordingly.\n * @default true\n */\n rememberChoice?: boolean;\n\n /** Display name of the requesting application. */\n appName?: string;\n\n /** Icon URL of the requesting application. */\n appIcon?: string;\n\n /**\n * Relay base URL override for the phone path. When omitted, each wallet's\n * `connectServerUrl` is discovered from its `/.well-known/enbox-connect`\n * document.\n */\n connectServerUrl?: string;\n\n /**\n * Path appended to the wallet origin to form the QR / deep-link target.\n * @default '/connect/app'\n */\n relayWalletPath?: string;\n\n /** Timeout in milliseconds for either method's handshake. */\n timeout?: number;\n\n /**\n * Color scheme. By default the modal follows the visitor's system\n * light/dark appearance; apps can force an appearance and/or override\n * palette tokens per scheme to match their brand.\n */\n theme?: ConnectModalTheme;\n\n /** DWN protocols and permission scopes being requested. */\n permissionRequests: ConnectPermissionRequest[];\n\n /** Internal dependency seams (tests). */\n deps?: Partial<ConnectModalDeps>;\n}\n\n/** Injectable collaborators, defaulted to the real implementations. */\nexport interface ConnectModalDeps {\n /** Runs one relay handshake (phone path). */\n runRelay: typeof runRelayConnect;\n\n /** Runs one popup handshake (browser path); must open the popup synchronously. */\n runPopup: (options: {\n walletUrl: string;\n permissionRequests: ConnectPermissionRequest[];\n appName: string;\n appIcon?: string;\n timeoutMs?: number;\n }) => Promise<ConnectResult | undefined>;\n\n /** Resolves a wallet origin to its relay `connectServerUrl` (or undefined). */\n discoverConnectServerUrl: (walletOrigin: string) => Promise<string | undefined>;\n\n /** Validates a pasted custom wallet URL. */\n validateWalletUrl: (origin: string) => Promise<boolean>;\n\n /** Whether to present the deep-link (same-device) variant of the phone path. */\n isMobile: () => boolean;\n\n /** Persistence for the remembered choice. */\n storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | undefined;\n}\n\n/**\n * Resolves a wallet origin to its relay `connectServerUrl` via the wallet's\n * `/.well-known/enbox-connect` document ({@link fetchWalletWellKnown} \u2014 the\n * same machinery the wallet selector uses for custom-URL validation).\n */\nexport async function discoverWalletConnectServerUrl(walletOrigin: string): Promise<string | undefined> {\n return (await fetchWalletWellKnown(walletOrigin))?.connectServerUrl;\n}\n\n/** Runs one popup handshake without collapsing early-close into a denial. */\nasync function runPopupConnect(options: {\n walletUrl: string;\n permissionRequests: ConnectPermissionRequest[];\n appName: string;\n appIcon?: string;\n timeoutMs?: number;\n}): Promise<ConnectResult | undefined> {\n // The transport constructor calls `window.open` synchronously \u2014 callers\n // must invoke this inside the user-gesture call stack.\n const transport = new PopupClientTransport({\n walletUrl : options.walletUrl,\n timeoutMs : options.timeoutMs,\n });\n const client = new ConnectClient({ transport });\n\n return await client.connect({\n appName : options.appName,\n appIcon : options.appIcon,\n clientMetadata : collectBrowserClientMetadata(),\n permissionRequests : options.permissionRequests,\n });\n}\n\nfunction defaultIsMobile(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n const coarse = window.matchMedia?.('(pointer: coarse)').matches ?? false;\n return coarse && Math.min(window.innerWidth, window.innerHeight) < 900;\n}\n\nfunction defaultDeps(): ConnectModalDeps {\n return {\n runRelay : runRelayConnect,\n runPopup : runPopupConnect,\n discoverConnectServerUrl : discoverWalletConnectServerUrl,\n validateWalletUrl : probeWalletWellKnown,\n isMobile : defaultIsMobile,\n storage : typeof localStorage === 'undefined' ? undefined : localStorage,\n };\n}\n\n/** Remembered method + wallet from a previous successful session. */\ninterface LastChoice {\n method: ConnectMethod;\n walletUrl: string;\n}\n\nfunction readLastChoice(storage: ConnectModalDeps['storage']): LastChoice | undefined {\n try {\n const raw = storage?.getItem(LAST_CHOICE_STORAGE_KEY);\n if (raw == null) {\n return undefined;\n }\n const parsed = JSON.parse(raw) as Partial<LastChoice>;\n if ((parsed.method === 'phone' || parsed.method === 'browser') && typeof parsed.walletUrl === 'string') {\n return { method: parsed.method, walletUrl: parsed.walletUrl };\n }\n } catch { /* unreadable storage \u2014 behave as first visit */ }\n return undefined;\n}\n\nfunction writeLastChoice(storage: ConnectModalDeps['storage'], choice: LastChoice): void {\n try {\n storage?.setItem(LAST_CHOICE_STORAGE_KEY, JSON.stringify(choice));\n } catch { /* best effort */ }\n}\n\n/** One cancellable relay session. */\ninterface RelaySession {\n cancelled: Promise<never>;\n cancel: () => void;\n active: boolean;\n}\n\nfunction createRelaySession(): RelaySession {\n let cancel!: () => void;\n const session: Partial<RelaySession> = { active: true };\n const cancelled = new Promise<never>((_, reject) => {\n cancel = (): void => {\n if (session.active === true) {\n session.active = false;\n reject(new RelayConnectCancelledError());\n }\n };\n });\n // Mark handled so an unconsumed cancellation never surfaces as unhandled.\n cancelled.catch((): undefined => undefined);\n session.cancelled = cancelled;\n session.cancel = cancel;\n return session as RelaySession;\n}\n\n/**\n * Opens the connect modal and resolves when the session ends.\n *\n * @returns The delegated credentials; `undefined` when the user denied the\n * request in the wallet (or dismissed after a denial).\n * @throws When the user cancels the modal, or the session fails and the\n * user dismisses the error.\n */\nexport function runConnectModal(options: ConnectModalOptions): Promise<ConnectResult | undefined> {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n throw new Error('[@enbox/browser] The connect modal is only available in browser environments.');\n }\n\n const deps: ConnectModalDeps = { ...defaultDeps(), ...options.deps };\n const wallets = dedupeWalletsByUrl(options.wallets ?? []);\n const rememberChoice = options.rememberChoice ?? true;\n const appName = options.appName ?? window.location.host;\n const relayWalletPath = options.relayWalletPath ?? '/connect/app';\n const isMobile = deps.isMobile();\n\n const lastChoice = rememberChoice ? readLastChoice(deps.storage) : undefined;\n\n // Wallet resolution order: explicit option \u2192 remembered \u2192 catalog head.\n const lockedWallet = options.walletUrl !== undefined;\n let walletUrl = options.walletUrl\n ?? (lastChoice !== undefined && (lockedWallet || walletInCatalog(wallets, lastChoice.walletUrl)) ? lastChoice.walletUrl : undefined)\n ?? wallets[0]?.url;\n\n // Method resolution order: explicit option \u2192 remembered \u2192 phone.\n let method: ConnectMethod = options.preferredMethod ?? lastChoice?.method ?? 'phone';\n\n return new Promise<ConnectResult | undefined>((resolve, reject) => {\n // \u2500\u2500 Host + shadow root \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const host = document.createElement('div');\n host.id = 'enbox-connect-modal';\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = MODAL_STYLES;\n shadow.appendChild(style);\n\n const overlay = document.createElement('div');\n overlay.className = 'overlay';\n const modal = document.createElement('div');\n modal.className = 'modal';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-label', `Connect to ${appName}`);\n\n // \u2500\u2500 Theme \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // System light/dark is pure CSS (`prefers-color-scheme`), so it tracks\n // the visitor live. A forced appearance pins the token block instead.\n const theme = options.theme ?? {};\n const appearance = theme.appearance ?? 'auto';\n if (appearance !== 'auto') {\n modal.setAttribute('data-appearance', appearance);\n }\n\n // Dapp palette overrides land as inline custom properties: setProperty\n // parses each value as a lone declaration, so a hostile string cannot\n // escape into the stylesheet.\n const systemDark = window.matchMedia?.('(prefers-color-scheme: dark)');\n const hasPaletteOverrides = theme.accent !== undefined || theme.accentContrast !== undefined\n || theme.light !== undefined || theme.dark !== undefined;\n const applyPaletteTokens = (): void => {\n const scheme = appearance === 'auto'\n ? (systemDark?.matches === true ? 'dark' : 'light')\n : appearance;\n const palette: ConnectModalPalette = {\n accent : theme.accent,\n accentContrast : theme.accentContrast,\n ...theme[scheme],\n };\n for (const key of Object.keys(PALETTE_TOKENS) as Array<keyof ConnectModalPalette>) {\n const value = palette[key];\n if (typeof value === 'string' && value.trim() !== '') {\n modal.style.setProperty(PALETTE_TOKENS[key], value);\n } else {\n modal.style.removeProperty(PALETTE_TOKENS[key]);\n }\n }\n };\n const onSchemeChange = (): void => applyPaletteTokens();\n if (hasPaletteOverrides) {\n applyPaletteTokens();\n if (appearance === 'auto') {\n systemDark?.addEventListener?.('change', onSchemeChange);\n }\n }\n\n // \u2500\u2500 Session state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let settled = false;\n let relaySession: RelaySession | undefined;\n let remintTimer: ReturnType<typeof setTimeout> | undefined;\n let remintAt: number | undefined;\n let popupBusy = false;\n let pinResolve: ((pin: string) => void) | undefined;\n const discoveryCache = new Map<string, Promise<string | undefined>>();\n\n // Collapsed identity row: the selected wallet plus the next catalog\n // wallets, never repeating one. Slots stay stable across in-row\n // switches (only the highlight moves); the row recomposes only when a\n // wallet from outside it \u2014 grid pick or custom URL \u2014 becomes selected,\n // which puts that wallet in the first slot.\n let rowWallets: WalletOption[] = [];\n\n /** The catalog entry for `url`, or a synthesized option for custom URLs. */\n const walletByUrl = (url: string): WalletOption =>\n wallets.find((wallet) => wallet.url === url) ?? { name: hostnameOf(url) ?? url, url };\n\n const composeWalletRow = (): void => {\n if (walletUrl === undefined) {\n rowWallets = wallets.slice(0, WALLET_ROW_SIZE);\n return;\n }\n if (rowWallets.some((wallet) => wallet.url === walletUrl)) {\n return;\n }\n const selected = walletByUrl(walletUrl);\n rowWallets = [selected, ...wallets.filter((wallet) => wallet.url !== selected.url)].slice(0, WALLET_ROW_SIZE);\n };\n\n const selectWallet = (url: string): void => {\n walletUrl = url;\n renderFooter();\n void startMethod();\n };\n\n const cleanup = (): void => {\n relaySession?.cancel();\n clearRemint();\n document.removeEventListener('keydown', onKeydown);\n document.removeEventListener('visibilitychange', onVisibilityReturn);\n systemDark?.removeEventListener?.('change', onSchemeChange);\n try { document.body.removeChild(host); } catch { /* best effort */ }\n };\n\n const settle = (settler: () => void): void => {\n if (settled) { return; }\n settled = true;\n cleanup();\n settler();\n };\n\n const succeed = (result: ConnectResult): void => {\n if (rememberChoice) {\n writeLastChoice(deps.storage, { method, walletUrl: walletUrl ?? '' });\n }\n renderConnected();\n const finish = (): void => settle(() => resolve(result));\n setTimeout(finish, 1_200);\n };\n\n const cancelModal = (): void => settle(() => reject(new Error('[@enbox/browser] Connect cancelled.')));\n\n // \u2500\u2500 Zones \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n modal.appendChild(buildHeader(appName, options.appIcon, cancelModal));\n\n const stage = document.createElement('div');\n stage.className = 'stage';\n stage.setAttribute('aria-live', 'polite');\n modal.appendChild(stage);\n\n const footer = document.createElement('div');\n footer.className = 'footer';\n modal.appendChild(footer);\n\n // \u2500\u2500 Stage renderers (all render in place; nothing navigates) \u2500\u2500\n const setStage = (...nodes: (HTMLElement | SVGElement)[]): void => {\n stage.replaceChildren(...nodes);\n stage.classList.remove('fade-in');\n void stage.offsetWidth; // restart the transition\n stage.classList.add('fade-in');\n };\n\n const renderBusy = (message: string): void => {\n setStage(el('div', 'spinner'), el('p', 'stage-caption', message));\n };\n\n /**\n * Schedules the \"finish in the wallet\" morph after a handoff link is\n * followed. Deferred one tick so the anchor's default new-tab navigation\n * completes before the anchor is replaced, and guarded so a session that\n * moved on meanwhile (re-mint, wallet response, settle) is never\n * overwritten.\n */\n const morphToAway = (walletName: string): void => {\n const session = relaySession;\n setTimeout((): void => {\n if (settled || session !== relaySession || session?.active !== true || pinResolve !== undefined) {\n return;\n }\n renderAway(walletName);\n }, 0);\n };\n\n /**\n * Builds one same-device handoff anchor for the wallet URI. The wallet\n * opens in a new tab so this modal \u2014 and the relay session under it \u2014\n * stays alive, with the pairing-code entry waiting when the user\n * switches back. `noopener` keeps the wallet tab from reaching back into\n * this one.\n */\n const buildHandoffLink = (handoff: WalletUriHandoff, walletName: string, className: string): HTMLAnchorElement => {\n const link = document.createElement('a');\n link.className = className;\n link.href = handoff.walletUri;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.addEventListener('click', () => { morphToAway(walletName); });\n return link;\n };\n\n const renderQr = (handoff: WalletUriHandoff): void => {\n const wallet = walletUrl !== undefined ? walletByUrl(walletUrl) : undefined;\n const walletName = wallet?.name ?? 'your wallet';\n\n // The QR card is itself a handoff link on every device: opening it on\n // this device runs the exact handshake the camera path runs on another\n // one, and scanning it keeps working either way.\n const qrLink = buildHandoffLink(handoff, walletName, 'qr-box qr-link');\n qrLink.setAttribute('aria-label', `Open ${walletName} on this device`);\n // Fixed colors on the white card: dark-on-light QRs scan reliably in\n // both appearances (inverted codes trip up some camera apps).\n qrLink.replaceChildren(qrToSvg(encodeQr(handoff.walletUri), {\n dark : '#14141f',\n light : 'transparent',\n quietZone : 2,\n }));\n\n // The selected wallet's mark sits at the QR centre \u2014 the \"this is the\n // wallet you're connecting to\" cue. The 44px plate over the ~180px\n // symbol occludes ~5% of modules, well inside ECC level M's 15%\n // recovery budget (the compact variant scales the plate down to\n // match).\n if (wallet !== undefined) {\n const logo = el('div', 'qr-logo');\n logo.appendChild(buildWalletIcon(wallet));\n qrLink.appendChild(logo);\n }\n\n if (isMobile) {\n const link = buildHandoffLink(handoff, walletName, 'deep-link');\n if (wallet !== undefined) {\n link.appendChild(buildWalletIcon(wallet));\n }\n link.appendChild(el('span', 'deep-link-label', `Continue in ${walletName}`));\n\n qrLink.classList.add('compact');\n setStage(\n link,\n el('p', 'stage-subline', `${walletName} opens in a new tab \u2014 approve there, then come back for your code.`),\n el('div', 'stage-divider', 'or scan with another phone'),\n qrLink,\n );\n return;\n }\n\n setStage(\n qrLink,\n el('p', 'stage-caption', 'Scan with your phone\u2019s camera'),\n el('p', 'stage-subline', `${walletName} stays on your phone \u2014 or click the code to open it here.`),\n );\n };\n\n /**\n * Shown once a handoff link is followed on this device: the approval is\n * happening in the wallet tab, this one waits for the code. \"Start over\"\n * mints a fresh pointer \u2014 the right recovery, because the pointer the\n * wallet tab carried away is single-use.\n */\n const renderAway = (walletName: string): void => {\n setStage(\n el('div', 'spinner'),\n el('p', 'stage-caption', `Finish in ${walletName}`),\n el('p', 'stage-subline', isMobile\n ? `Approve the connection in the ${walletName} tab, then come back here for your code.`\n : 'Approve the connection in the tab that just opened, then come back here for your code.'),\n stageLinkButton('Start over', () => { void startPhone(); }),\n );\n };\n\n const renderClaimed = (): void => {\n const walletName = walletUrl !== undefined ? walletByUrl(walletUrl).name : 'your wallet';\n const pulse = document.createElement('div');\n pulse.className = 'claimed-pulse';\n setStage(\n pulse,\n el('p', 'stage-caption', `Request received \u2014 approve in ${walletName}`),\n el('p', 'stage-subline', 'Once you approve, you\u2019ll get a code to enter here.'),\n );\n };\n\n const renderPin = (attempt: number, previousError?: Error): Promise<string> => {\n return new Promise<string>((resolvePin) => {\n pinResolve = resolvePin;\n const walletName = walletUrl !== undefined ? walletByUrl(walletUrl).name : 'your wallet';\n\n const boxes = document.createElement('div');\n boxes.className = 'pin-row';\n if (previousError !== undefined) {\n boxes.classList.add('shake');\n }\n\n const inputs: HTMLInputElement[] = [];\n for (let i = 0; i < PIN_LENGTH; i++) {\n const input = document.createElement('input');\n input.className = 'pin-input';\n input.type = 'text';\n input.inputMode = 'numeric';\n input.maxLength = 1;\n input.setAttribute('aria-label', `Code digit ${i + 1}`);\n inputs.push(input);\n boxes.appendChild(input);\n }\n\n const submitIfComplete = (): void => {\n const code = inputs.map((i) => i.value).join('');\n if (code.length === PIN_LENGTH && pinResolve !== undefined) {\n const resolveOnce = pinResolve;\n pinResolve = undefined;\n renderBusy('Checking the code\u2026');\n resolveOnce(code);\n }\n };\n\n inputs.forEach((input, index) => {\n input.addEventListener('input', () => {\n input.value = input.value.replace(/\\D/g, '').slice(0, 1);\n if (input.value !== '' && index + 1 < inputs.length) {\n inputs[index + 1].focus();\n }\n submitIfComplete();\n });\n input.addEventListener('keydown', (event) => {\n if (event.key === 'Backspace' && input.value === '' && index > 0) {\n inputs[index - 1].focus();\n }\n });\n input.addEventListener('paste', (event) => {\n const digits = (event.clipboardData?.getData('text') ?? '').replace(/\\D/g, '').slice(0, PIN_LENGTH);\n if (digits.length === 0) { return; }\n event.preventDefault();\n digits.split('').forEach((digit, digitIndex) => {\n if (inputs[digitIndex] !== undefined) {\n inputs[digitIndex].value = digit;\n }\n });\n inputs[Math.min(digits.length, PIN_LENGTH) - 1]?.focus();\n submitIfComplete();\n });\n });\n\n setStage(\n el('p', 'stage-caption', `Enter the code shown in ${walletName}`),\n boxes,\n ...(previousError !== undefined\n ? [el('p', 'stage-error', `That code doesn\u2019t match \u2014 check ${walletName}.`)]\n : [el('p', 'stage-subline', attempt === 1 ? 'This confirms you\u2019re the one approving.' : '')]),\n );\n\n inputs[0].focus();\n });\n };\n\n const renderConnected = (): void => {\n const check = el('div', 'check');\n check.textContent = '\u2713';\n setStage(check, el('p', 'stage-caption', 'You\u2019re connected.'));\n };\n\n const renderDenied = (): void => {\n setStage(\n el('p', 'stage-caption', 'No problem \u2014 nothing was shared.'),\n stageButton('Start over', () => { void startMethod(); }),\n stageLinkButton('Close', () => settle(() => resolve(undefined))),\n );\n };\n\n const renderError = (message: string, error?: Error): void => {\n setStage(\n el('p', 'stage-caption', message),\n stageButton('Start over', () => { void startMethod(); }),\n stageLinkButton('Close', () => settle(() => reject(error ?? new Error(`[@enbox/browser] ${message}`)))),\n );\n };\n\n const renderPhoneUnavailable = (): void => {\n setStage(\n el('p', 'stage-caption', 'This wallet can\u2019t connect by phone here.'),\n el('p', 'stage-subline', 'You can continue in this browser instead.'),\n stageButton('Use this browser', () => { startPopup(); }),\n );\n };\n\n // The popup surface is a small window on desktop but a new tab on\n // phones \u2014 the copy names whichever the visitor will actually see.\n const popupSurface = isMobile ? 'tab' : 'window';\n\n const renderPopupPrompt = (): void => {\n setStage(\n el('p', 'stage-caption', 'Connect with a wallet in this browser'),\n el('p', 'stage-subline', isMobile\n ? 'Your wallet opens in a new tab to approve this connection \u2014 no code needed.'\n : 'Your wallet opens in a small window to approve this connection.'),\n stageButton(isMobile ? 'Open wallet' : 'Open wallet window', () => { startPopup(); }),\n );\n };\n\n const renderPopupWaiting = (): void => {\n setStage(\n el('div', 'spinner'),\n el('p', 'stage-caption', `Finish in the wallet ${popupSurface}`),\n el('p', 'stage-subline', 'We\u2019ll wrap up here as soon as you\u2019re done.'),\n );\n };\n\n const renderPopupInterrupted = (blocked: boolean): void => {\n setStage(\n el('p', 'stage-caption', blocked\n ? `Your browser blocked the wallet ${popupSurface}.`\n : `The wallet ${popupSurface} was closed.`),\n stageButton(blocked ? 'Open it now' : `Reopen ${popupSurface}`, () => { startPopup(); }),\n stageLinkButton(isMobile ? 'Use a code instead' : 'Use your phone instead', () => { void switchMethod('phone'); }),\n );\n };\n\n const renderPopupFailure = (error: unknown): void => {\n if (settled) { return; }\n\n const failure = error instanceof Error ? error : new Error(String(error));\n const popupBlocked = /popup blocked/i.test(failure.message);\n if (error instanceof PopupWindowClosedError || popupBlocked) {\n renderPopupInterrupted(popupBlocked);\n return;\n }\n\n renderError(\n /timed out/i.test(failure.message)\n ? 'That took too long, so we stopped for safety.'\n : 'Something went wrong while connecting.',\n failure,\n );\n };\n\n // \u2500\u2500 Method drivers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const resolveConnectServerUrl = async (origin: string): Promise<string | undefined> => {\n if (options.connectServerUrl !== undefined) {\n return options.connectServerUrl;\n }\n let cached = discoveryCache.get(origin);\n if (cached === undefined) {\n cached = deps.discoverConnectServerUrl(origin);\n discoveryCache.set(origin, cached);\n }\n return cached;\n };\n\n const clearRemint = (): void => {\n clearTimeout(remintTimer);\n remintAt = undefined;\n };\n\n const remintNow = (): void => {\n // Never re-mint once the wallet has responded (pairing in progress).\n if (!settled && pinResolve === undefined && method === 'phone') {\n void startPhone();\n }\n };\n\n const scheduleRemint = (expiresInSeconds: number): void => {\n clearRemint();\n const delay = Math.max(REMINT_MIN_MS, expiresInSeconds * 1_000 - REMINT_SAFETY_MS);\n // The deadline is kept alongside the timer: background tabs (mobile\n // especially) throttle or freeze timers, so the visibility handler\n // re-checks it when the user returns.\n remintAt = Date.now() + delay;\n remintTimer = setTimeout(remintNow, delay);\n };\n\n const startPhone = async (): Promise<void> => {\n relaySession?.cancel();\n clearRemint();\n\n if (walletUrl === undefined) {\n renderError('No wallet is configured.');\n return;\n }\n\n method = 'phone';\n renderFooter();\n renderBusy('Getting things ready\u2026');\n\n const origin = new URL(walletUrl).origin;\n const connectServerUrl = await resolveConnectServerUrl(origin);\n if (connectServerUrl === undefined) {\n renderPhoneUnavailable();\n return;\n }\n\n const session = createRelaySession();\n relaySession = session;\n\n try {\n const result = await deps.runRelay({\n connectServerUrl,\n walletUri : new URL(relayWalletPath, origin).toString(),\n appName,\n appIcon : options.appIcon,\n clientMetadata : collectBrowserClientMetadata(),\n permissionRequests : options.permissionRequests,\n timeoutMs : options.timeout,\n cancelled : session.cancelled,\n onWalletUriReady : (handoff): void => {\n if (session.active && !settled) {\n renderQr(handoff);\n scheduleRemint(handoff.expiresIn);\n }\n },\n onClaimed: (): void => {\n if (session.active && !settled) {\n // The wallet has the request \u2014 stop re-minting (a new pointer\n // would orphan the approval in progress) and show progress.\n clearRemint();\n renderClaimed();\n }\n },\n requestPin: (attempt, previousError): Promise<string> => {\n clearRemint();\n return renderPin(attempt, previousError);\n },\n });\n\n if (!session.active || settled) { return; }\n\n if (result === undefined) {\n renderDenied();\n } else {\n succeed(result);\n }\n } catch (error) {\n if (!session.active || settled || error instanceof RelayConnectCancelledError) {\n return;\n }\n const failure = error instanceof Error ? error : new Error(String(error));\n renderError(\n /timed out/i.test(failure.message)\n ? 'That took too long, so we stopped for safety.'\n : 'Something went wrong while connecting.',\n failure,\n );\n }\n };\n\n const startPopup = (): void => {\n // Synchronous popup open inside the click's call stack.\n relaySession?.cancel();\n clearRemint();\n\n if (walletUrl === undefined) {\n renderError('No wallet is configured.');\n return;\n }\n if (popupBusy) { return; }\n\n method = 'browser';\n renderFooter();\n\n popupBusy = true;\n renderPopupWaiting();\n\n try {\n deps.runPopup({\n walletUrl,\n permissionRequests : options.permissionRequests,\n appName,\n appIcon : options.appIcon,\n timeoutMs : options.timeout,\n })\n .then((result) => {\n if (settled) { return; }\n if (result === undefined) {\n renderDenied();\n } else {\n succeed(result);\n }\n })\n .catch(renderPopupFailure)\n .finally(() => { popupBusy = false; });\n } catch (error) {\n popupBusy = false;\n renderPopupFailure(error);\n }\n };\n\n const startMethod = async (): Promise<void> => {\n if (method === 'browser') {\n // window.open must stay inside a user gesture \u2014 prompt for the click.\n relaySession?.cancel();\n clearRemint();\n renderFooter();\n renderPopupPrompt();\n } else {\n await startPhone();\n }\n };\n\n const switchMethod = async (next: ConnectMethod): Promise<void> => {\n method = next;\n await startMethod();\n };\n\n // \u2500\u2500 Footer: identity row (+ catalog panel), method link below \u2500\u2500\n const renderFooter = (): void => {\n footer.replaceChildren();\n\n if (!lockedWallet) {\n composeWalletRow();\n const switcher = buildWalletSwitcher();\n if (switcher.label !== undefined) {\n footer.appendChild(switcher.label);\n }\n footer.appendChild(switcher.row);\n footer.appendChild(switcher.panel);\n }\n\n const row = document.createElement('div');\n row.className = 'footer-row';\n\n if (method === 'phone') {\n const alt = document.createElement('button');\n alt.className = 'footer-link method-link';\n // On a phone both methods open the wallet on this device \u2014 what the\n // popup channel actually buys the visitor is skipping the code.\n alt.textContent = isMobile ? 'Or connect without a code \u2192' : 'No phone? Use this browser \u2192';\n // startPopup runs synchronously in this click handler.\n alt.addEventListener('click', () => { startPopup(); });\n row.appendChild(alt);\n } else {\n const alt = document.createElement('button');\n alt.className = 'footer-link method-link';\n alt.textContent = isMobile ? 'Use a code instead \u2192' : 'Use your phone instead \u2192';\n alt.addEventListener('click', () => { void switchMethod('phone'); });\n row.appendChild(alt);\n }\n\n if (row.childElementCount > 0) {\n footer.appendChild(row);\n }\n };\n\n const buildWalletSwitcher = (): { label?: HTMLElement; row: HTMLDivElement; panel: HTMLDivElement } => {\n // Identity row: selected wallet + the next catalog wallets, then the\n // More tile expanding the full catalog in place.\n const row = document.createElement('div');\n row.className = 'wallet-row';\n row.setAttribute('role', 'radiogroup');\n row.setAttribute('aria-label', 'Wallet');\n\n for (const wallet of rowWallets) {\n const tile = document.createElement('button');\n tile.className = 'row-tile';\n tile.title = wallet.description ?? wallet.name;\n tile.setAttribute('role', 'radio');\n const isSelected = wallet.url === walletUrl;\n tile.setAttribute('aria-checked', isSelected ? 'true' : 'false');\n if (isSelected) {\n tile.classList.add('selected');\n }\n tile.appendChild(buildWalletIcon(wallet));\n tile.appendChild(el('span', 'row-tile-name', wallet.name));\n tile.addEventListener('click', () => {\n if (wallet.url !== walletUrl) {\n selectWallet(wallet.url);\n }\n });\n row.appendChild(tile);\n }\n\n const panel = document.createElement('div');\n panel.className = 'wallet-panel';\n panel.hidden = true;\n\n // The panel grid holds only the wallets NOT already visible in the\n // row, so expanding never shows the same wallet twice.\n const gridWallets = wallets.filter((wallet) => !rowWallets.some((shown) => shown.url === wallet.url));\n\n const more = document.createElement('button');\n more.className = 'row-tile more-tile';\n more.title = 'All wallets';\n more.setAttribute('aria-expanded', 'false');\n more.appendChild(el('span', 'more-count', gridWallets.length > 0 ? `+${gridWallets.length}` : '\u22EF'));\n more.appendChild(el('span', 'row-tile-name', 'More'));\n more.addEventListener('click', () => {\n panel.hidden = !panel.hidden;\n more.setAttribute('aria-expanded', panel.hidden ? 'false' : 'true');\n if (!panel.hidden) {\n updateScrollHint();\n }\n });\n row.appendChild(more);\n\n const label = rowWallets.length > 0 ? el('div', 'wallet-row-label', 'Connecting with') : undefined;\n\n // Search filter \u2014 appears once the grid outgrows one row of tiles.\n const tiles: Array<{ wallet: (typeof wallets)[number]; el: HTMLButtonElement }> = [];\n const empty = document.createElement('div');\n empty.className = 'wallet-empty';\n empty.textContent = 'No other wallets match your search.';\n empty.hidden = true;\n\n if (gridWallets.length > WALLET_SEARCH_THRESHOLD) {\n const search = document.createElement('input');\n search.type = 'search';\n search.className = 'wallet-search';\n search.placeholder = 'Search wallets\u2026';\n search.setAttribute('aria-label', 'Search wallets');\n search.addEventListener('input', () => {\n const query = search.value.trim().toLowerCase();\n let visible = 0;\n for (const { wallet, el: tile } of tiles) {\n const match = query === ''\n || wallet.name.toLowerCase().includes(query)\n || wallet.url.toLowerCase().includes(query);\n tile.hidden = !match;\n if (match) { visible += 1; }\n }\n empty.hidden = visible > 0;\n updateScrollHint();\n });\n panel.appendChild(search);\n }\n\n // Tiles matching the identity row, four per row; past three rows the\n // grid scrolls in place, with a bottom fade hinting at more below.\n const scrollWrap = document.createElement('div');\n scrollWrap.className = 'wallet-scroll-wrap';\n scrollWrap.hidden = gridWallets.length === 0;\n const scroll = document.createElement('div');\n scroll.className = 'wallet-scroll';\n const grid = document.createElement('div');\n grid.className = 'wallet-grid';\n\n const updateScrollHint = (): void => {\n const overflowing = scroll.scrollHeight - scroll.clientHeight > 1;\n const atEnd = scroll.scrollTop + scroll.clientHeight >= scroll.scrollHeight - 1;\n scrollWrap.classList.toggle('scroll-hint', overflowing && !atEnd);\n };\n scroll.addEventListener('scroll', updateScrollHint);\n\n for (const wallet of gridWallets) {\n const tile = document.createElement('button');\n tile.className = 'wallet-tile';\n tile.title = wallet.description ?? wallet.name;\n tile.appendChild(buildWalletIcon(wallet));\n const tileName = document.createElement('span');\n tileName.className = 'wallet-tile-name';\n tileName.textContent = wallet.name;\n tile.appendChild(tileName);\n tile.addEventListener('click', () => {\n selectWallet(wallet.url);\n });\n tiles.push({ wallet, el: tile });\n grid.appendChild(tile);\n }\n scroll.appendChild(grid);\n scroll.appendChild(empty);\n scrollWrap.appendChild(scroll);\n panel.appendChild(scrollWrap);\n\n // Custom wallet URL (the power-user path, demoted to the disclosure).\n const custom = document.createElement('div');\n custom.className = 'wallet-custom';\n const input = document.createElement('input');\n input.className = 'url-input';\n input.type = 'url';\n input.placeholder = 'https://your-wallet.example';\n const go = document.createElement('button');\n go.className = 'url-go';\n go.textContent = 'Use';\n const urlError = document.createElement('div');\n urlError.className = 'url-error';\n urlError.hidden = true;\n\n // When validation fails we let the user override, since the connect\n // handshake is the ultimate gate \u2014 a valid wallet behind strict CORS\n // should not be permanently blocked.\n let allowUnverified = false;\n\n const submitCustom = async (): Promise<void> => {\n const value = input.value.trim();\n if (value === '') { return; }\n let origin: string;\n try {\n origin = new URL(value.includes('://') ? value : `https://${value}`).origin;\n } catch {\n input.classList.add('invalid');\n return;\n }\n if (allowUnverified) {\n selectWallet(origin);\n return;\n }\n go.disabled = true;\n go.textContent = 'Checking\u2026';\n urlError.hidden = true;\n const valid = await deps.validateWalletUrl(origin);\n go.disabled = false;\n if (valid) {\n go.textContent = 'Use';\n selectWallet(origin);\n return;\n }\n allowUnverified = true;\n go.textContent = 'Use anyway';\n input.classList.add('invalid');\n urlError.textContent = `Couldn't verify a wallet at ${origin}.`;\n urlError.hidden = false;\n };\n\n input.addEventListener('input', () => {\n allowUnverified = false;\n go.textContent = 'Use';\n input.classList.remove('invalid');\n urlError.hidden = true;\n });\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') { void submitCustom(); }\n });\n go.addEventListener('click', () => { void submitCustom(); });\n custom.appendChild(input);\n custom.appendChild(go);\n panel.appendChild(custom);\n panel.appendChild(urlError);\n\n return { label, row, panel };\n };\n\n // \u2500\u2500 Global interactions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n overlay.addEventListener('click', (event) => {\n if (event.target === overlay) {\n cancelModal();\n }\n });\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n cancelModal();\n return;\n }\n if (event.key === 'Tab') {\n trapFocus(shadow, event);\n }\n };\n document.addEventListener('keydown', onKeydown);\n\n // The visitor typically comes back from the wallet tab mid-session.\n const onVisibilityReturn = (): void => {\n if (document.visibilityState !== 'visible' || settled) {\n return;\n }\n\n // Background tabs throttle (or freeze) timers, so a re-mint that came\n // due while the user was away fires now instead of never.\n if (remintAt !== undefined && Date.now() >= remintAt) {\n remintNow();\n return;\n }\n\n // Returning with the code in hand: put the caret in the first empty\n // pairing-code box so they can type it straight away.\n if (pinResolve !== undefined) {\n const inputs = Array.from(shadow.querySelectorAll<HTMLInputElement>('.pin-input'));\n inputs.find((input) => input.value === '')?.focus();\n }\n };\n document.addEventListener('visibilitychange', onVisibilityReturn);\n\n overlay.appendChild(modal);\n shadow.appendChild(overlay);\n document.body.appendChild(host);\n\n renderFooter();\n void startMethod();\n });\n}\n\n// \u2500\u2500\u2500 Small DOM helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction walletInCatalog(wallets: WalletOption[], url: string): boolean {\n return wallets.some((wallet) => wallet.url === url);\n}\n\n/** Drops catalog entries that repeat an earlier wallet's URL. */\nfunction dedupeWalletsByUrl(wallets: WalletOption[]): WalletOption[] {\n return wallets.filter((wallet, index) => wallets.findIndex((candidate) => candidate.url === wallet.url) === index);\n}\n\n/** Compact display form of a wallet URL for the switcher toggle. */\nfunction hostnameOf(url: string | undefined): string | undefined {\n if (url === undefined) {\n return undefined;\n }\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n\nfunction el(tag: string, className: string, text?: string): HTMLElement {\n const node = document.createElement(tag);\n node.className = className;\n if (text !== undefined) {\n node.textContent = text;\n }\n return node;\n}\n\nfunction stageButton(label: string, onClick: () => void): HTMLButtonElement {\n const button = document.createElement('button');\n button.className = 'stage-btn';\n button.textContent = label;\n button.addEventListener('click', onClick);\n return button;\n}\n\nfunction stageLinkButton(label: string, onClick: () => void): HTMLButtonElement {\n const button = document.createElement('button');\n button.className = 'footer-link';\n button.textContent = label;\n button.addEventListener('click', onClick);\n return button;\n}\n\nfunction buildHeader(appName: string, appIcon: string | undefined, onCancel: () => void): HTMLDivElement {\n const header = document.createElement('div');\n header.className = 'header';\n\n const identity = document.createElement('div');\n identity.className = 'header-identity';\n\n if (appIcon !== undefined) {\n const icon = document.createElement('img');\n icon.className = 'header-icon';\n icon.src = appIcon;\n icon.alt = '';\n icon.width = 24;\n icon.height = 24;\n icon.addEventListener('error', () => icon.remove());\n identity.appendChild(icon);\n }\n\n const title = document.createElement('h2');\n title.textContent = `Connect to ${appName}`;\n identity.appendChild(title);\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'close-btn';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.textContent = '\\u00d7';\n closeBtn.addEventListener('click', onCancel);\n\n header.appendChild(identity);\n header.appendChild(closeBtn);\n return header;\n}\n\nfunction trapFocus(shadow: ShadowRoot, event: KeyboardEvent): void {\n const focusables = Array.from(\n shadow.querySelectorAll<HTMLElement>('button, input, a[href], [tabindex]:not([tabindex=\"-1\"])'),\n ).filter((node) => !node.hasAttribute('disabled') && node.offsetParent !== null);\n\n if (focusables.length === 0) {\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = shadow.activeElement as HTMLElement | null;\n\n if (event.shiftKey && (active === first || active === null)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n}\n\n// \u2500\u2500\u2500 Styles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// One static sheet; every color reads a `--ec-*` token. Light values sit on\n// `.modal`, dark values apply under `prefers-color-scheme` (so the system\n// appearance tracks live) and under a forced `data-appearance`. Dapp\n// palette overrides land as inline custom properties, which outrank all of\n// these \u2014 nothing user-provided is ever concatenated into this string.\n\n/** Light-appearance design tokens. */\nconst LIGHT_TOKENS = `\n --ec-bg: #ffffff;\n --ec-surface: #f5f6f8;\n --ec-text: #17171f;\n --ec-muted: #63636e;\n --ec-border: #e3e4e9;\n --ec-accent: #0a62d0;\n --ec-accent-contrast: #ffffff;\n --ec-danger: #c0392b;\n --ec-success: #1e9e5a;`;\n\n/** Dark-appearance design tokens. */\nconst DARK_TOKENS = `\n --ec-bg: #181822;\n --ec-surface: #23232f;\n --ec-text: #e9e9f0;\n --ec-muted: #9a9aa6;\n --ec-border: #33333f;\n --ec-accent: #58a6ff;\n --ec-accent-contrast: #0b1526;\n --ec-danger: #ff7a7a;\n --ec-success: #43d17c;`;\n\nconst MODAL_STYLES = `\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n /* Keep the hidden attribute authoritative: author display values (e.g.\n the panel's flex) would otherwise override the UA's [hidden] rule and\n leave \"collapsed\" sections permanently expanded. */\n [hidden] { display: none !important; }\n\n .overlay {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n background: rgba(0, 0, 0, 0.5);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n animation: fadeIn 0.15s ease-out;\n }\n\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }\n @keyframes stageIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes shake {\n 0%, 100% { transform: translateX(0); }\n 20%, 60% { transform: translateX(-6px); }\n 40%, 80% { transform: translateX(6px); }\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes claimedPulse {\n 0%, 100% { transform: scale(0.85); opacity: 0.7; }\n 50% { transform: scale(1); opacity: 1; }\n }\n\n .modal {${LIGHT_TOKENS}\n --ec-accent-soft: color-mix(in srgb, var(--ec-accent) 14%, transparent);\n background: var(--ec-bg);\n color: var(--ec-text);\n border-radius: 16px;\n width: 400px;\n max-width: 100%;\n max-height: calc(100vh - 32px);\n overflow-y: auto;\n padding: 16px 20px 12px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);\n animation: slideUp 0.2s ease-out;\n display: flex;\n flex-direction: column;\n }\n @media (prefers-color-scheme: dark) {\n .modal {${DARK_TOKENS}\n }\n }\n .modal[data-appearance='light'] {${LIGHT_TOKENS}\n }\n .modal[data-appearance='dark'] {${DARK_TOKENS}\n }\n\n button, input { font-family: inherit; }\n button:focus-visible, a:focus-visible {\n outline: 2px solid var(--ec-accent);\n outline-offset: 2px;\n }\n\n .header { display: flex; justify-content: space-between; align-items: center; gap: 8px; }\n .header-identity { display: flex; align-items: center; gap: 10px; min-width: 0; }\n .header-icon { border-radius: 6px; flex-shrink: 0; }\n h2 { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n .close-btn {\n background: none; border: none; font-size: 24px; cursor: pointer;\n color: var(--ec-muted); padding: 4px 8px; border-radius: 8px; line-height: 1;\n flex-shrink: 0;\n }\n .close-btn:hover { color: var(--ec-text); background: var(--ec-surface); }\n\n .stage {\n min-height: 240px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n text-align: center;\n padding: 12px 0 10px;\n }\n .stage.fade-in > * { animation: stageIn 0.15s ease-out; }\n\n .qr-box {\n position: relative;\n width: 200px;\n height: 200px;\n padding: 10px;\n border-radius: 12px;\n background: #ffffff;\n border: 1px solid #e3e4e9;\n }\n .qr-box svg { width: 100%; height: 100%; display: block; }\n\n /* Selected wallet's mark on the QR centre. Like the card, the plate is\n theme-invariant white so the logo sits on a scannable ground. */\n .qr-logo {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 44px;\n height: 44px;\n border-radius: 10px;\n background: #ffffff;\n border: 1px solid #e3e4e9;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .qr-logo .wallet-icon { width: 30px; height: 30px; }\n .qr-logo .wallet-badge { border-radius: 8px; font-size: 15px; }\n\n /* The QR card doubles as the same-device handoff link. */\n a.qr-box { display: block; cursor: pointer; }\n .qr-box.qr-link:hover {\n border-color: var(--ec-accent);\n box-shadow: 0 0 0 3px var(--ec-accent-soft);\n }\n .qr-box.compact { width: 160px; height: 160px; }\n .qr-box.compact .qr-logo { width: 36px; height: 36px; }\n .qr-box.compact .qr-logo .wallet-icon { width: 24px; height: 24px; }\n\n .stage-divider {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n color: var(--ec-muted);\n font-size: 12px;\n }\n .stage-divider::before, .stage-divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--ec-border);\n }\n\n .claimed-pulse {\n width: 64px; height: 64px; border-radius: 50%;\n background: var(--ec-accent-soft); position: relative;\n }\n .claimed-pulse::after {\n content: ''; position: absolute; inset: 18px; border-radius: 50%;\n background: var(--ec-accent);\n animation: claimedPulse 1.6s ease-in-out infinite;\n }\n\n .stage-caption { font-size: 15px; font-weight: 600; }\n .stage-subline { font-size: 13px; color: var(--ec-muted); max-width: 300px; line-height: 1.45; }\n .stage-error { font-size: 13px; color: var(--ec-danger); }\n\n .deep-link {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n width: 100%;\n padding: 13px 16px;\n border-radius: 12px;\n background: var(--ec-accent);\n color: var(--ec-accent-contrast);\n font-weight: 600;\n font-size: 15px;\n text-decoration: none;\n }\n .deep-link .wallet-icon { width: 24px; height: 24px; }\n .deep-link .wallet-badge {\n border-radius: 6px;\n font-size: 12px;\n background: var(--ec-accent-contrast);\n }\n .deep-link .wallet-img { border-radius: 6px; }\n\n .pin-row { display: flex; gap: 10px; }\n .pin-row.shake { animation: shake 0.4s ease-in-out; }\n .pin-input {\n width: 46px; height: 54px;\n text-align: center;\n font-size: 24px; font-weight: 600;\n color: var(--ec-text);\n background: var(--ec-surface);\n border: 1px solid var(--ec-border);\n border-radius: 10px;\n outline: none;\n }\n .pin-input:focus { border-color: var(--ec-accent); }\n\n .check {\n width: 56px; height: 56px;\n display: flex; align-items: center; justify-content: center;\n border-radius: 50%;\n background: var(--ec-success);\n color: #ffffff;\n font-size: 28px;\n }\n\n .spinner {\n width: 32px; height: 32px;\n border-radius: 50%;\n border: 3px solid var(--ec-border);\n border-top-color: var(--ec-accent);\n animation: spin 0.8s linear infinite;\n }\n\n .stage-btn {\n padding: 10px 20px;\n border: none;\n border-radius: 10px;\n background: var(--ec-accent);\n color: var(--ec-accent-contrast);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n }\n .stage-btn:hover { filter: brightness(1.08); }\n\n .footer {\n border-top: 1px solid var(--ec-border);\n padding-top: 8px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .footer-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 2px 8px;\n }\n .footer-row > * { min-width: 0; }\n .footer-row > :only-child { margin-inline: auto; }\n\n .footer-link {\n background: none;\n border: none;\n color: var(--ec-muted);\n font-size: 13px;\n cursor: pointer;\n padding: 5px 8px;\n border-radius: 8px;\n }\n .footer-link:hover { color: var(--ec-text); background: var(--ec-surface); }\n .method-link { color: var(--ec-accent); }\n\n .wallet-row-label { font-size: 12px; color: var(--ec-muted); padding: 2px 2px 0; }\n\n .wallet-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n }\n .row-tile, .wallet-tile {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 10px 6px;\n min-width: 0;\n background: var(--ec-surface);\n border: 1px solid var(--ec-border);\n border-radius: 12px;\n color: var(--ec-text);\n font-size: 11px;\n cursor: pointer;\n }\n .row-tile:hover, .wallet-tile:hover { border-color: var(--ec-accent); }\n .row-tile.selected {\n border-color: var(--ec-accent);\n background: var(--ec-accent-soft);\n box-shadow: inset 0 0 0 1px var(--ec-accent);\n }\n .row-tile.selected .row-tile-name { font-weight: 600; }\n .row-tile .wallet-icon, .wallet-tile .wallet-icon { width: 28px; height: 28px; }\n .row-tile-name, .wallet-tile-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n .more-tile { color: var(--ec-muted); }\n .more-tile:hover { color: var(--ec-text); }\n .more-tile[aria-expanded='true'] { border-color: var(--ec-accent); }\n .more-count {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n background: var(--ec-accent-soft);\n color: var(--ec-accent);\n }\n\n .wallet-panel { width: 100%; padding: 4px 0 2px; display: flex; flex-direction: column; gap: 8px; }\n .wallet-search {\n width: 100%; padding: 8px 12px;\n border-radius: 10px; border: 1px solid var(--ec-border); background: transparent;\n color: inherit; font: inherit; font-size: 13px;\n }\n .wallet-search:focus { outline: none; border-color: var(--ec-accent); }\n\n /* Cap the grid at three rows of tiles; past that it scrolls in place,\n and the wrapper's bottom fade hints that more wallets are below. */\n .wallet-scroll-wrap { position: relative; }\n .wallet-scroll { max-height: 220px; overflow-y: auto; }\n .wallet-scroll-wrap.scroll-hint::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n height: 28px;\n background: linear-gradient(to bottom, transparent, var(--ec-bg));\n pointer-events: none;\n }\n .wallet-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n }\n\n .wallet-icon { position: relative; width: 28px; height: 28px; flex-shrink: 0; display: inline-flex; }\n .wallet-badge {\n width: 100%; height: 100%; border-radius: 8px; display: inline-flex;\n align-items: center; justify-content: center; font-size: 13px;\n font-weight: 600; background: var(--ec-accent-soft); color: var(--ec-accent);\n }\n .wallet-img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 8px; object-fit: cover; }\n\n .wallet-empty { padding: 10px 4px; font-size: 12px; color: var(--ec-muted); text-align: center; }\n\n .wallet-custom { display: flex; gap: 6px; }\n .url-input {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid var(--ec-border);\n border-radius: 10px;\n font-size: 13px;\n background: var(--ec-surface);\n color: var(--ec-text);\n outline: none;\n }\n .url-input:focus { border-color: var(--ec-accent); }\n .url-input.invalid { border-color: var(--ec-danger); }\n .url-go {\n padding: 8px 14px;\n border: none;\n border-radius: 10px;\n background: var(--ec-accent);\n color: var(--ec-accent-contrast);\n font-size: 13px;\n cursor: pointer;\n }\n .url-error { font-size: 12px; color: var(--ec-danger); }\n\n @media (prefers-reduced-motion: reduce) {\n .overlay, .modal, .stage.fade-in > *, .pin-row.shake { animation: none; }\n .claimed-pulse::after { animation: none; }\n }\n`;\n", "/**\n * Wallet icon builder shared by the connect modal's wallet switcher.\n *\n * Prefers the wallet's own favicon and degrades to a letter badge. We never\n * call a third-party favicon proxy: those 404 for many origins and leak the\n * wallet URL to the proxy.\n *\n * @module\n */\n\nimport type { WalletOption } from '../browser-connect-handler.js';\n\n/** Build a wallet icon element (own favicon with a letter-badge fallback). */\nexport function buildWalletIcon(wallet: WalletOption): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = 'wallet-icon';\n\n const badge = document.createElement('span');\n badge.className = 'wallet-badge';\n badge.textContent = wallet.name.charAt(0).toUpperCase();\n wrap.appendChild(badge);\n\n const sources = iconCandidates(wallet);\n if (sources.length === 0) {\n return wrap;\n }\n\n const img = document.createElement('img');\n img.className = 'wallet-img';\n img.alt = '';\n img.width = 28;\n img.height = 28;\n\n let index = 0;\n img.addEventListener('error', () => {\n index += 1;\n if (index < sources.length) {\n img.src = sources[index];\n } else {\n img.remove(); // fall back to the letter badge\n }\n });\n\n img.src = sources[index];\n wrap.appendChild(img);\n return wrap;\n}\n\n/** Ordered favicon URLs to try for a wallet, most specific first. */\nfunction iconCandidates(wallet: WalletOption): string[] {\n if (wallet.icon !== undefined) {\n return [wallet.icon];\n }\n\n let origin: string;\n try {\n origin = new URL(wallet.url).origin;\n } catch {\n return [];\n }\n\n return [`${origin}/favicon.svg`, `${origin}/favicon.ico`, `${origin}/favicon.png`];\n}\n", "/**\n * DWeb Connect client \u2014 the dapp side of the popup/postMessage connect flow.\n *\n * {@link PopupClientTransport} implements the `@enbox/connect` kernel's\n * `ConnectTransport` over a wallet popup:\n *\n * 1. The dapp opens `${walletUrl}/dweb-connect` as a popup window.\n * 2. The wallet emits a `loaded` beacon carrying a fresh ephemeral X25519\n * public key and its origin.\n * 3. The kernel seals the signed connect request to that key (ECDH-ES,\n * `apv` bound to the wallet origin) and the transport posts the\n * ciphertext to the popup.\n * 4. The wallet posts back the sealed response JWE (or the deny token),\n * which the kernel opens and value-checks.\n *\n * Only ciphertext crosses the postMessage channel. Every message is checked\n * against the wallet origin derived from the configured wallet URL (never\n * `'*'`), and against the popup window as `event.source`.\n *\n * @module\n */\n\nimport type { Jwk } from '@enbox/crypto';\nimport type {\n ConnectClientMetadata,\n ConnectPermissionRequest,\n ConnectRequestProfile,\n ConnectResult,\n ConnectTransport,\n} from '@enbox/connect';\n\nimport { assertX25519PublicJwk, CONNECT_DENIED_TOKEN, ConnectClient } from '@enbox/connect';\n\nimport {\n DWEB_CONNECT_ACK_MESSAGE_TYPE,\n DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n DWEB_CONNECT_PATH,\n DWEB_CONNECT_REQUEST_MESSAGE_TYPE,\n DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n getTrustedMessage,\n} from './dweb-connect-messages.js';\n\n/** Default budget for the whole popup handshake (beacon + user consent + response). */\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\n/** Interval at which the transport checks whether the user closed the popup. */\nconst CLOSED_POLL_INTERVAL_MS = 500;\n\n/**\n * Grace period after the popup is seen closed for an already-posted response\n * to finish delivery before the close is treated as a denial.\n */\nconst CLOSED_RESPONSE_GRACE_MS = 1_500;\n\n/** Window name given to the wallet popup. */\nconst POPUP_WINDOW_NAME = 'enbox-dweb-connect';\n\n/** Outer size of the wallet popup window. */\nconst POPUP_WIDTH = 500;\nconst POPUP_HEIGHT = 700;\n\n/**\n * Builds the wallet popup's window features, centring it over the opener\n * window \u2014 without `left`/`top` browsers park the popup wherever they like\n * (usually offset into a corner). Falls back to centring on the screen when\n * the opener's metrics are unavailable, and lets the browser clamp\n * off-screen coordinates. Mobile browsers ignore the features entirely and\n * open a tab.\n */\nfunction popupWindowFeatures(): string {\n const base = `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},menubar=no,toolbar=no,location=no,status=no`;\n\n // `screenX`/`outerWidth` describe the opener window; `screen.avail*`\n // describe its monitor \u2014 so the popup lands on the same display.\n const openerWidth = window.outerWidth > 0 ? window.outerWidth : (window.screen?.availWidth ?? 0);\n const openerHeight = window.outerHeight > 0 ? window.outerHeight : (window.screen?.availHeight ?? 0);\n if (openerWidth === 0 || openerHeight === 0) {\n return base;\n }\n\n const left = Math.max(0, Math.round((window.screenX ?? 0) + (openerWidth - POPUP_WIDTH) / 2));\n const top = Math.max(0, Math.round((window.screenY ?? 0) + (openerHeight - POPUP_HEIGHT) / 2));\n return `${base},left=${left},top=${top}`;\n}\n\n/** Guards against calling browser-only entry points outside a browser. */\nfunction assertBrowserEnvironment(): void {\n if (typeof window === 'undefined') {\n throw new Error('[@enbox/browser] DWeb Connect is only available in browser environments.');\n }\n}\n\n/**\n * Thrown when the user closes the wallet popup before the wallet finished\n * loading (i.e. before its `loaded` beacon arrived). Callers typically treat\n * this the same as a user denial.\n */\nexport class PopupWindowClosedError extends Error {\n constructor() {\n super('[@enbox/browser] Wallet popup was closed before the wallet finished loading.');\n this.name = 'PopupWindowClosedError';\n }\n}\n\n/** Options for constructing a {@link PopupClientTransport}. */\nexport type PopupClientTransportOptions = {\n /** Base URL of the wallet app (e.g. `https://enbox-wallet.pages.dev`). */\n walletUrl: string;\n\n /**\n * Total budget in milliseconds for the popup handshake. The popup is closed\n * and the handshake rejected when the wallet has not responded in time.\n * @default 300_000 (5 minutes)\n */\n timeoutMs?: number;\n};\n\n/**\n * Popup/postMessage {@link ConnectTransport} for browser dapps.\n *\n * Single-use: construct a new transport per handshake. The **constructor**\n * opens the wallet popup synchronously \u2014 so `window.open` runs inside the user\n * gesture, ahead of the kernel's awaited key generation, and survives strict\n * popup blockers; `requestProfile()` then awaits the wallet's `loaded` beacon;\n * `deliverRequest()` posts the sealed request ciphertext; `awaitResponse()`\n * resolves with the sealed response JWE, or the deny token when the user denies\n * or closes the popup after the handshake was established.\n *\n * Security properties:\n * - `targetOrigin` of every outbound `postMessage` is pinned to the origin\n * derived from `walletUrl` \u2014 never `'*'`.\n * - Inbound messages are dropped unless `event.origin` equals the pinned\n * wallet origin AND `event.source` is the popup window this transport opened.\n * - The beacon's `walletOrigin` field must equal the pinned origin, and its\n * `walletEpk` must be a public-only X25519 JWK; a malformed beacon from the\n * genuine popup fails the handshake closed.\n */\nexport class PopupClientTransport implements ConnectTransport {\n /** {@inheritDoc ConnectTransport.requiresPin} */\n public readonly requiresPin: boolean = false;\n\n private readonly _walletOrigin: string;\n private readonly _timeoutMs: number;\n\n private readonly _popup: Window;\n private _settled = false;\n private _walletEpkReceived = false;\n private _timeoutId?: ReturnType<typeof setTimeout>;\n private _closedPollId?: ReturnType<typeof setInterval>;\n private _messageListener?: (event: MessageEvent) => void;\n\n private readonly _walletEpkPromise: Promise<Jwk>;\n private _resolveWalletEpk?: (walletEpk: Jwk) => void;\n private _rejectWalletEpk?: (error: Error) => void;\n\n private readonly _responsePromise: Promise<string>;\n private _resolveResponse?: (payload: string) => void;\n private _rejectResponse?: (error: Error) => void;\n\n constructor(options: PopupClientTransportOptions) {\n assertBrowserEnvironment();\n\n this._walletOrigin = new URL(options.walletUrl).origin;\n this._timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n // Open the wallet popup SYNCHRONOUSLY, in the user-gesture call stack,\n // before the kernel's awaited `DidJwk.create()` / `X25519.generateKey()`\n // run. Strict popup blockers (Safari) reject a `window.open` issued once\n // the stack has yielded to a prior `await`, so opening it here \u2014 instead of\n // inside the awaited `requestProfile()` \u2014 is what keeps the flow usable.\n const popupUrl = new URL(DWEB_CONNECT_PATH, options.walletUrl).toString();\n const popup = window.open(popupUrl, POPUP_WINDOW_NAME, popupWindowFeatures());\n if (!popup) {\n throw new Error('[@enbox/browser] Popup blocked. Allow popups for this site to connect to a wallet.');\n }\n this._popup = popup;\n\n this._walletEpkPromise = new Promise<Jwk>((resolve, reject): void => {\n this._resolveWalletEpk = resolve;\n this._rejectWalletEpk = reject;\n });\n\n // Created up-front so a response (or deny) arriving before\n // `awaitResponse()` is called is never dropped. The no-op catch marks\n // early rejections (timeout, popup closed during load) as handled until\n // the kernel attaches its own handlers via `awaitResponse()`.\n this._responsePromise = new Promise<string>((resolve, reject): void => {\n this._resolveResponse = resolve;\n this._rejectResponse = reject;\n });\n this._responsePromise.catch((): undefined => undefined);\n\n // Listen synchronously, before the wallet page can emit its `loaded`\n // beacon, so the beacon is never missed while the kernel awaits key\n // generation ahead of `requestProfile()`.\n this._messageListener = (event: MessageEvent): void => { this.onMessage(event); };\n window.addEventListener('message', this._messageListener);\n\n this._timeoutId = setTimeout((): void => {\n this.fail(new Error('[@enbox/browser] DWeb Connect timed out waiting for wallet response.'));\n }, this._timeoutMs);\n\n this._closedPollId = setInterval((): void => { this.onClosedPoll(); }, CLOSED_POLL_INTERVAL_MS);\n }\n\n /**\n * Awaits the already-open popup's `loaded` beacon, then returns the popup\n * channel profile: ECDH-ES encryption to the beacon's ephemeral key with the\n * pinned wallet origin as the `apv` binding, a `post_message` reply\n * descriptor, and the client-supplied `state` correlator.\n *\n * The popup was opened synchronously at construction, so this method only\n * awaits the beacon \u2014 it never issues the blocker-sensitive `window.open`.\n *\n * @param state - The handshake correlator minted by the {@link ConnectClient}.\n * @throws If the user closes the popup before the beacon arrives\n * ({@link PopupWindowClosedError}), the beacon is malformed, or on\n * timeout.\n */\n public async requestProfile(state: string): Promise<ConnectRequestProfile> {\n const walletEpk = await this._walletEpkPromise;\n\n return {\n encryption : { mode: 'ecdh-es', walletEpk, walletOrigin: this._walletOrigin },\n reply : { mode: 'post_message' },\n state,\n };\n }\n\n /**\n * Posts the sealed request ciphertext to the wallet popup with the\n * `targetOrigin` pinned to the wallet origin.\n */\n public async deliverRequest(jwe: string): Promise<void> {\n this._popup.postMessage({ type: DWEB_CONNECT_REQUEST_MESSAGE_TYPE, jwe }, this._walletOrigin);\n }\n\n /**\n * Awaits the wallet's response ciphertext: the sealed response JWE, or the\n * deny token when the user denies in the wallet or closes the popup.\n * Rejects on timeout.\n */\n public async awaitResponse(): Promise<string> {\n return await this._responsePromise;\n }\n\n /**\n * {@inheritDoc ConnectTransport.confirmComplete}\n *\n * Posts the payload-less ack to the wallet popup (pinned `targetOrigin`)\n * so a wallet still holding its \"finishing up\" screen can flip to a\n * confirmed \"connected\" state before closing itself. A popup the user\n * already closed is skipped silently.\n */\n public async confirmComplete(): Promise<void> {\n if (this._popup.closed === true) { return; }\n this._popup.postMessage({ type: DWEB_CONNECT_ACK_MESSAGE_TYPE }, this._walletOrigin);\n }\n\n private onMessage(event: MessageEvent): void {\n const message = getTrustedMessage(event, this._walletOrigin, this._popup);\n if (message === undefined) { return; }\n\n if (message.type === DWEB_CONNECT_LOADED_MESSAGE_TYPE) {\n this.onLoadedBeacon(message);\n return;\n }\n\n if (message.type === DWEB_CONNECT_RESPONSE_MESSAGE_TYPE) {\n this.onResponseMessage(message);\n }\n }\n\n private onLoadedBeacon(message: Record<string, unknown>): void {\n if (this._settled || this._walletEpkReceived) { return; }\n\n // The beacon passed the origin and source checks, so a malformed payload\n // is a protocol violation by the genuine popup \u2014 fail closed. The X25519\n // public-JWK shape check is delegated to the connect kernel.\n let walletEpk: Jwk;\n try {\n assertX25519PublicJwk(message.walletEpk);\n walletEpk = message.walletEpk;\n } catch {\n this.fail(new Error('[@enbox/browser] Wallet loaded beacon did not carry a valid X25519 public key.'));\n return;\n }\n\n if (message.walletOrigin !== this._walletOrigin) {\n this.fail(new Error('[@enbox/browser] Wallet loaded beacon origin does not match the configured wallet origin.'));\n return;\n }\n\n this._walletEpkReceived = true;\n this._resolveWalletEpk?.(walletEpk);\n }\n\n private onResponseMessage(message: Record<string, unknown>): void {\n if (this._settled) { return; }\n\n if (typeof message.payload !== 'string') {\n this.fail(new Error('[@enbox/browser] Wallet response message did not carry a ciphertext payload.'));\n return;\n }\n\n this._settled = true;\n this.cleanup();\n // No-op on the normal path; unblocks `requestProfile()` if a response\n // somehow arrives before the beacon.\n this._rejectWalletEpk?.(new Error('[@enbox/browser] Wallet responded before the handshake was established.'));\n this._resolveResponse?.(message.payload);\n }\n\n private onClosedPoll(): void {\n if (this._settled || this._popup.closed !== true) { return; }\n\n if (!this._walletEpkReceived) {\n // Closed before the wallet ever loaded \u2014 the handshake cannot proceed.\n this.fail(new PopupWindowClosedError());\n return;\n }\n\n // Closed after the handshake was established. A wallet that posts its\n // response and immediately closes itself can lose the race between that\n // final message and this poll \u2014 especially when this page was\n // backgrounded (mobile tabs) and both signals arrive together on\n // resume \u2014 so give a queued response a grace window before treating the\n // close as a user denial.\n clearInterval(this._closedPollId);\n setTimeout((): void => {\n if (this._settled) { return; }\n this._settled = true;\n this.cleanup();\n this._resolveResponse?.(CONNECT_DENIED_TOKEN);\n }, CLOSED_RESPONSE_GRACE_MS);\n }\n\n private fail(error: Error): void {\n if (this._settled) { return; }\n this._settled = true;\n this.cleanup();\n try { this._popup.close(); } catch { /* best effort */ }\n this._rejectWalletEpk?.(error);\n this._rejectResponse?.(error);\n }\n\n private cleanup(): void {\n clearTimeout(this._timeoutId);\n clearInterval(this._closedPollId);\n if (this._messageListener !== undefined) {\n window.removeEventListener('message', this._messageListener);\n this._messageListener = undefined;\n }\n }\n}\n\n/** Options for a one-shot {@link connectViaPopup} flow. */\nexport type PopupConnectOptions = {\n /** Base URL of the wallet app (e.g. `https://enbox-wallet.pages.dev`). */\n walletUrl: string;\n\n /** DWN protocols and permission scopes to request from the wallet. */\n permissionRequests: ConnectPermissionRequest[];\n\n /**\n * Timeout in milliseconds for the popup handshake.\n * @default 300_000 (5 minutes)\n */\n timeout?: number;\n\n /**\n * Display name of the requesting application, shown in the wallet's\n * consent screen. Defaults to the dapp's host.\n */\n appName?: string;\n\n /**\n * Icon URL of the requesting application, shown alongside the app name in\n * the wallet's consent screen.\n */\n appIcon?: string;\n};\n\n/** Collects self-reported environment hints for the wallet's session display. */\nexport function collectBrowserClientMetadata(): ConnectClientMetadata {\n const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();\n const languages = Array.isArray(globalThis.navigator.languages)\n ? globalThis.navigator.languages.filter((language) => typeof language === 'string' && language.length > 0)\n : undefined;\n\n return {\n origin : globalThis.location.origin,\n userAgent : globalThis.navigator.userAgent,\n platform : globalThis.navigator.platform,\n language : globalThis.navigator.language,\n ...(languages && languages.length > 0 ? { languages } : {}),\n ...(resolvedOptions.timeZone ? { timezone: resolvedOptions.timeZone } : {}),\n };\n}\n\n/**\n * Runs one DWeb Connect popup handshake end-to-end: opens the wallet popup,\n * drives the `@enbox/connect` kernel client over a {@link PopupClientTransport},\n * and returns the delegated credentials.\n *\n * @returns The delegate credentials, or `undefined` when the user denied the\n * request or closed the popup.\n * @throws If the popup is blocked, the handshake times out, or the wallet\n * returns an invalid response.\n */\nexport async function connectViaPopup(options: PopupConnectOptions): Promise<ConnectResult | undefined> {\n const transport = new PopupClientTransport({\n walletUrl : options.walletUrl,\n timeoutMs : options.timeout,\n });\n const client = new ConnectClient({ transport });\n\n try {\n return await client.connect({\n appName : options.appName ?? globalThis.location.host,\n appIcon : options.appIcon,\n clientMetadata : collectBrowserClientMetadata(),\n permissionRequests : options.permissionRequests,\n });\n } catch (error) {\n if (error instanceof PopupWindowClosedError) {\n // The user closed the wallet before it loaded \u2014 same as a denial.\n return undefined;\n }\n throw error;\n }\n}\n", "/**\n * Wire shapes for the DWeb Connect popup/postMessage channel.\n *\n * The dapp and the wallet exchange exactly four message kinds over\n * `window.postMessage`:\n *\n * 1. `loaded` beacon (wallet \u2192 dapp): announces the wallet page is ready and\n * carries a fresh ephemeral X25519 public key plus the wallet's origin.\n * 2. `request` (dapp \u2192 wallet): the sealed connect request JWE \u2014 ciphertext\n * only, encrypted to the beacon key with ECDH-ES and the wallet origin\n * bound into the JWE `apv` header.\n * 3. `response` (wallet \u2192 dapp): the sealed connect response JWE, or the\n * literal deny token \u2014 again ciphertext only.\n * 4. `ack` (dapp \u2192 wallet): payload-less completion signal \u2014 the dapp opened\n * the response successfully, so the wallet can flip to a confirmed\n * \"connected\" state before closing itself. Optional and observational;\n * wallets unaware of it simply ignore the message.\n *\n * Plaintext never crosses the channel, and both sides pin `targetOrigin`\n * and verify `event.origin` / `event.source` on every message.\n *\n * @module\n */\n\nimport type { Jwk } from '@enbox/crypto';\n\n/** Path of the wallet's DWeb Connect page, opened as a popup by the dapp. */\nexport const DWEB_CONNECT_PATH = '/dweb-connect';\n\n/** Message type of the wallet's `loaded` beacon (wallet \u2192 dapp). */\nexport const DWEB_CONNECT_LOADED_MESSAGE_TYPE = 'enbox-connect-loaded';\n\n/** Message type carrying the sealed connect request JWE (dapp \u2192 wallet). */\nexport const DWEB_CONNECT_REQUEST_MESSAGE_TYPE = 'enbox-connect-request';\n\n/** Message type carrying the sealed connect response JWE or deny token (wallet \u2192 dapp). */\nexport const DWEB_CONNECT_RESPONSE_MESSAGE_TYPE = 'enbox-connect-response';\n\n/** Message type of the dapp's completion acknowledgement (dapp \u2192 wallet). */\nexport const DWEB_CONNECT_ACK_MESSAGE_TYPE = 'enbox-connect-ack';\n\n/**\n * The wallet's readiness beacon. Emitted to `window.opener` once the wallet's\n * DWeb Connect page has generated its per-session ephemeral X25519 key.\n */\nexport type DWebConnectLoadedMessage = {\n type: typeof DWEB_CONNECT_LOADED_MESSAGE_TYPE;\n\n /** Fresh ephemeral X25519 public JWK the dapp seals the request to. */\n walletEpk: Jwk;\n\n /** The wallet's own origin; must match the origin the dapp has pinned. */\n walletOrigin: string;\n};\n\n/** The dapp's sealed connect request, posted to the wallet popup. */\nexport type DWebConnectRequestMessage = {\n type: typeof DWEB_CONNECT_REQUEST_MESSAGE_TYPE;\n\n /** The sealed connect request as a Compact JWE string. */\n jwe: string;\n};\n\n/** The wallet's sealed connect response, posted back to the opener. */\nexport type DWebConnectResponseMessage = {\n type: typeof DWEB_CONNECT_RESPONSE_MESSAGE_TYPE;\n\n /** The sealed connect response JWE, or the literal `CONNECT_DENIED_TOKEN`. */\n payload: string;\n};\n\n/**\n * The dapp's completion acknowledgement: it opened the wallet's response\n * successfully. Carries no payload by design.\n */\nexport type DWebConnectAckMessage = {\n type: typeof DWEB_CONNECT_ACK_MESSAGE_TYPE;\n};\n\n/**\n * Applies the shared inbound-message trust filter for the popup channel:\n * pins the message to the expected `event.origin`, pins its `event.source` to\n * the expected window, and requires a non-null object payload.\n *\n * Returns the payload cast to a plain record when every check passes, or\n * `undefined` when the message must be dropped. Both the dapp-side and\n * wallet-side transports early-return on `undefined` before inspecting any\n * message field \u2014 this is the security-critical filter that keeps hostile\n * origins and stray windows off the channel.\n */\nexport function getTrustedMessage(\n event: MessageEvent,\n expectedOrigin: string,\n expectedSource: Window | undefined,\n): Record<string, unknown> | undefined {\n // Origin pinning: only messages from the expected origin count.\n if (event.origin !== expectedOrigin) { return undefined; }\n\n // Source pinning: the message must come from the expected window.\n if (event.source !== expectedSource) { return undefined; }\n\n const data: unknown = event.data;\n if (typeof data !== 'object' || data === null) { return undefined; }\n\n return data as Record<string, unknown>;\n}\n", "/**\n * Minimal QR code encoder \u2014 dependency-free, byte mode, ECC level M,\n * versions 1\u201310 with automatic version selection and standard mask\n * evaluation (ISO/IEC 18004 penalty rules N1\u2013N4).\n *\n * Scope is deliberately narrow: it exists to render wallet-connect URIs in\n * the connect modal without adding a third-party runtime dependency. The\n * encoding pipeline follows the standard exactly \u2014 segment \u2192 codewords \u2192\n * Reed-Solomon blocks \u2192 interleave \u2192 placement \u2192 mask \u2014 and the test suite\n * verifies full module-matrix equality against the `qrcode` npm package\n * (dev-only oracle) across versions and mask patterns.\n *\n * @module\n */\n\n/** An encoded QR symbol: `modules[y][x]` is `true` for dark modules. */\nexport interface QrCode {\n /** Symbol width/height in modules (17 + 4\u00D7version). */\n size: number;\n\n /** Dark/light module matrix, row-major. */\n modules: boolean[][];\n\n /** Symbol version (1\u201310). */\n version: number;\n\n /** Applied mask pattern (0\u20137). */\n mask: number;\n}\n\n/** Error-correction level M codewords per block, indexed by version (1\u201310). */\nconst ECC_PER_BLOCK = [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26];\n\n/** Error-correction level M block counts, indexed by version (1\u201310). */\nconst NUM_BLOCKS = [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5];\n\n/** Total codewords in the symbol, indexed by version (1\u201310). */\nconst TOTAL_CODEWORDS = [-1, 26, 44, 70, 100, 134, 172, 196, 242, 292, 346];\n\n/** Format-info error-correction bits for level M (`00` per the standard). */\nconst FORMAT_ECL_M = 0b00;\n\nconst MAX_VERSION = 10;\n\n/** Data codeword capacity for level M at `version`. */\nfunction dataCodewords(version: number): number {\n return TOTAL_CODEWORDS[version] - ECC_PER_BLOCK[version] * NUM_BLOCKS[version];\n}\n\n/**\n * Encodes UTF-8 text as a byte-mode QR symbol at ECC level M.\n *\n * @param text - The payload; encoded as UTF-8 bytes.\n * @param forcedMask - Optional mask override (0\u20137); defaults to the\n * penalty-minimising mask per the standard.\n * @returns The encoded symbol.\n * @throws If the payload does not fit in a version-10 level-M symbol.\n */\nexport function encodeQr(text: string, forcedMask?: number): QrCode {\n const data = new TextEncoder().encode(text);\n\n // \u2500\u2500 Version selection: smallest version that fits the segment. \u2500\u2500\n let version = 0;\n for (let candidate = 1; candidate <= MAX_VERSION; candidate++) {\n const capacityBits = dataCodewords(candidate) * 8;\n const headerBits = 4 + (candidate <= 9 ? 8 : 16);\n if (headerBits + data.length * 8 <= capacityBits) {\n version = candidate;\n break;\n }\n }\n if (version === 0) {\n throw new Error(`[@enbox/browser] QR payload too long (${data.length} bytes exceeds version ${MAX_VERSION}-M capacity).`);\n }\n\n // \u2500\u2500 Segment bits: mode 0100, char count, data, terminator, padding. \u2500\u2500\n const bits: number[] = [];\n const pushBits = (value: number, length: number): void => {\n for (let i = length - 1; i >= 0; i--) {\n bits.push((value >>> i) & 1);\n }\n };\n\n pushBits(0b0100, 4);\n pushBits(data.length, version <= 9 ? 8 : 16);\n for (const byte of data) {\n pushBits(byte, 8);\n }\n\n const capacityBits = dataCodewords(version) * 8;\n pushBits(0, Math.min(4, capacityBits - bits.length)); // terminator\n pushBits(0, (8 - (bits.length % 8)) % 8); // byte align\n\n const padBytes = [0xEC, 0x11];\n for (let i = 0; bits.length < capacityBits; i++) {\n pushBits(padBytes[i % 2], 8);\n }\n\n const codewords = new Uint8Array(capacityBits / 8);\n for (let i = 0; i < bits.length; i++) {\n codewords[i >> 3] |= bits[i] << (7 - (i & 7));\n }\n\n // \u2500\u2500 Reed-Solomon blocks + interleave. \u2500\u2500\n const allCodewords = buildInterleavedCodewords(codewords, version);\n\n // \u2500\u2500 Module placement. \u2500\u2500\n const size = 17 + 4 * version;\n const modules: boolean[][] = Array.from({ length: size }, () => new Array<boolean>(size).fill(false));\n const isFunction: boolean[][] = Array.from({ length: size }, () => new Array<boolean>(size).fill(false));\n\n drawFunctionPatterns(modules, isFunction, version);\n drawCodewords(modules, isFunction, allCodewords);\n\n // \u2500\u2500 Mask selection: apply each mask, score, keep the best. \u2500\u2500\n let mask = forcedMask ?? -1;\n if (mask === -1) {\n let bestPenalty = Infinity;\n for (let candidate = 0; candidate < 8; candidate++) {\n applyMask(modules, isFunction, candidate);\n drawFormatBits(modules, isFunction, candidate);\n const penalty = computePenalty(modules);\n if (penalty < bestPenalty) {\n bestPenalty = penalty;\n mask = candidate;\n }\n applyMask(modules, isFunction, candidate); // undo (XOR is involutive)\n }\n }\n\n applyMask(modules, isFunction, mask);\n drawFormatBits(modules, isFunction, mask);\n\n return { size, modules, version, mask };\n}\n\n/** Splits data codewords into level-M blocks, computes ECC, interleaves. */\nfunction buildInterleavedCodewords(data: Uint8Array, version: number): Uint8Array {\n const numBlocks = NUM_BLOCKS[version];\n const eccLen = ECC_PER_BLOCK[version];\n const totalCodewords = TOTAL_CODEWORDS[version];\n\n const numShortBlocks = numBlocks - (totalCodewords % numBlocks);\n const shortBlockLen = Math.floor(totalCodewords / numBlocks);\n\n const blocks: Uint8Array[] = [];\n const eccBlocks: Uint8Array[] = [];\n const rsDivisor = reedSolomonDivisor(eccLen);\n\n let offset = 0;\n for (let i = 0; i < numBlocks; i++) {\n const dataLen = shortBlockLen - eccLen + (i < numShortBlocks ? 0 : 1);\n const block = data.slice(offset, offset + dataLen);\n offset += dataLen;\n blocks.push(block);\n eccBlocks.push(reedSolomonRemainder(block, rsDivisor));\n }\n\n const result = new Uint8Array(totalCodewords);\n let index = 0;\n const maxDataLen = shortBlockLen - eccLen + 1;\n for (let i = 0; i < maxDataLen; i++) {\n for (let b = 0; b < numBlocks; b++) {\n if (i < blocks[b].length) {\n result[index++] = blocks[b][i];\n }\n }\n }\n for (let i = 0; i < eccLen; i++) {\n for (let b = 0; b < numBlocks; b++) {\n result[index++] = eccBlocks[b][i];\n }\n }\n\n return result;\n}\n\n// \u2500\u2500 GF(256) Reed-Solomon (polynomial 0x11D) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction gfMultiply(x: number, y: number): number {\n let z = 0;\n for (let i = 7; i >= 0; i--) {\n z = (z << 1) ^ ((z >>> 7) * 0x11D);\n z ^= ((y >>> i) & 1) * x;\n }\n return z & 0xFF;\n}\n\n/** Generator polynomial coefficients for `degree` ECC codewords. */\nfunction reedSolomonDivisor(degree: number): Uint8Array {\n const result = new Uint8Array(degree);\n result[degree - 1] = 1;\n\n let root = 1;\n for (let i = 0; i < degree; i++) {\n for (let j = 0; j < degree; j++) {\n result[j] = gfMultiply(result[j], root);\n if (j + 1 < degree) {\n result[j] ^= result[j + 1];\n }\n }\n root = gfMultiply(root, 0x02);\n }\n return result;\n}\n\nfunction reedSolomonRemainder(data: Uint8Array, divisor: Uint8Array): Uint8Array {\n const result = new Uint8Array(divisor.length);\n for (const byte of data) {\n const factor = byte ^ result[0];\n result.copyWithin(0, 1);\n result[result.length - 1] = 0;\n for (let i = 0; i < divisor.length; i++) {\n result[i] ^= gfMultiply(divisor[i], factor);\n }\n }\n return result;\n}\n\n// \u2500\u2500 Function patterns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Alignment pattern centre coordinates, indexed by version (1\u201310). */\nconst ALIGNMENT_POSITIONS: number[][] = [\n [], [],\n [6, 18], [6, 22], [6, 26], [6, 30], [6, 34],\n [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50],\n];\n\nfunction setFunctionModule(\n modules: boolean[][],\n isFunction: boolean[][],\n x: number,\n y: number,\n dark: boolean,\n): void {\n modules[y][x] = dark;\n isFunction[y][x] = true;\n}\n\nfunction drawFunctionPatterns(modules: boolean[][], isFunction: boolean[][], version: number): void {\n const size = modules.length;\n\n // Timing patterns.\n for (let i = 0; i < size; i++) {\n setFunctionModule(modules, isFunction, 6, i, i % 2 === 0);\n setFunctionModule(modules, isFunction, i, 6, i % 2 === 0);\n }\n\n // Finder patterns (with separators) at three corners.\n drawFinderPattern(modules, isFunction, 3, 3);\n drawFinderPattern(modules, isFunction, size - 4, 3);\n drawFinderPattern(modules, isFunction, 3, size - 4);\n\n // Alignment patterns: all pairs except the three finder corners.\n const positions = ALIGNMENT_POSITIONS[version];\n for (let i = 0; i < positions.length; i++) {\n for (let j = 0; j < positions.length; j++) {\n const skip =\n (i === 0 && j === 0) ||\n (i === 0 && j === positions.length - 1) ||\n (i === positions.length - 1 && j === 0);\n if (!skip) {\n drawAlignmentPattern(modules, isFunction, positions[i], positions[j]);\n }\n }\n }\n\n // Format-info reserved areas (drawn with mask later, but the modules must\n // be marked as function modules before codeword placement).\n drawFormatBits(modules, isFunction, 0);\n\n // Dark module.\n setFunctionModule(modules, isFunction, 8, size - 8, true);\n\n // Version information (versions \u2265 7).\n if (version >= 7) {\n drawVersionBits(modules, isFunction, version);\n }\n}\n\nfunction drawFinderPattern(modules: boolean[][], isFunction: boolean[][], cx: number, cy: number): void {\n const size = modules.length;\n for (let dy = -4; dy <= 4; dy++) {\n for (let dx = -4; dx <= 4; dx++) {\n const x = cx + dx;\n const y = cy + dy;\n if (x < 0 || x >= size || y < 0 || y >= size) {\n continue;\n }\n const distance = Math.max(Math.abs(dx), Math.abs(dy));\n setFunctionModule(modules, isFunction, x, y, distance !== 2 && distance !== 4);\n }\n }\n}\n\nfunction drawAlignmentPattern(modules: boolean[][], isFunction: boolean[][], cx: number, cy: number): void {\n for (let dy = -2; dy <= 2; dy++) {\n for (let dx = -2; dx <= 2; dx++) {\n setFunctionModule(modules, isFunction, cx + dx, cy + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);\n }\n }\n}\n\n/** 15-bit format info: 5 data bits BCH(15,5)-expanded, XORed with 0x5412. */\nfunction drawFormatBits(modules: boolean[][], isFunction: boolean[][], mask: number): void {\n const size = modules.length;\n\n const data = (FORMAT_ECL_M << 3) | mask;\n let rem = data;\n for (let i = 0; i < 10; i++) {\n rem = (rem << 1) ^ ((rem >>> 9) * 0x537);\n }\n const bits = ((data << 10) | rem) ^ 0x5412;\n\n // Around the top-left finder.\n for (let i = 0; i <= 5; i++) {\n setFunctionModule(modules, isFunction, 8, i, ((bits >>> i) & 1) !== 0);\n }\n setFunctionModule(modules, isFunction, 8, 7, ((bits >>> 6) & 1) !== 0);\n setFunctionModule(modules, isFunction, 8, 8, ((bits >>> 7) & 1) !== 0);\n setFunctionModule(modules, isFunction, 7, 8, ((bits >>> 8) & 1) !== 0);\n for (let i = 9; i < 15; i++) {\n setFunctionModule(modules, isFunction, 14 - i, 8, ((bits >>> i) & 1) !== 0);\n }\n\n // Second copy: below the top-right finder and beside the bottom-left one.\n for (let i = 0; i < 8; i++) {\n setFunctionModule(modules, isFunction, size - 1 - i, 8, ((bits >>> i) & 1) !== 0);\n }\n for (let i = 8; i < 15; i++) {\n setFunctionModule(modules, isFunction, 8, size - 15 + i, ((bits >>> i) & 1) !== 0);\n }\n}\n\n/** 18-bit version info (versions \u2265 7): 6 data bits + BCH(18,6) remainder. */\nfunction drawVersionBits(modules: boolean[][], isFunction: boolean[][], version: number): void {\n const size = modules.length;\n\n let rem = version;\n for (let i = 0; i < 12; i++) {\n rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);\n }\n const bits = (version << 12) | rem;\n\n for (let i = 0; i < 18; i++) {\n const bit = ((bits >>> i) & 1) !== 0;\n const a = size - 11 + (i % 3);\n const b = Math.floor(i / 3);\n setFunctionModule(modules, isFunction, a, b, bit);\n setFunctionModule(modules, isFunction, b, a, bit);\n }\n}\n\n/** Zig-zag codeword placement over non-function modules. */\nfunction drawCodewords(modules: boolean[][], isFunction: boolean[][], codewords: Uint8Array): void {\n const size = modules.length;\n let bitIndex = 0;\n\n for (let right = size - 1; right >= 1; right -= 2) {\n if (right === 6) {\n right = 5;\n }\n for (let vertical = 0; vertical < size; vertical++) {\n for (let j = 0; j < 2; j++) {\n const x = right - j;\n const upward = ((right + 1) & 2) === 0;\n const y = upward ? size - 1 - vertical : vertical;\n if (!isFunction[y][x] && bitIndex < codewords.length * 8) {\n modules[y][x] = ((codewords[bitIndex >> 3] >>> (7 - (bitIndex & 7))) & 1) !== 0;\n bitIndex++;\n }\n }\n }\n }\n}\n\n/** XORs the mask pattern over non-function modules (involutive). */\nfunction applyMask(modules: boolean[][], isFunction: boolean[][], mask: number): void {\n const size = modules.length;\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n if (isFunction[y][x]) {\n continue;\n }\n let invert: boolean;\n switch (mask) {\n case 0: invert = (x + y) % 2 === 0; break;\n case 1: invert = y % 2 === 0; break;\n case 2: invert = x % 3 === 0; break;\n case 3: invert = (x + y) % 3 === 0; break;\n case 4: invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0; break;\n case 5: invert = ((x * y) % 2) + ((x * y) % 3) === 0; break;\n case 6: invert = (((x * y) % 2) + ((x * y) % 3)) % 2 === 0; break;\n default: invert = (((x + y) % 2) + ((x * y) % 3)) % 2 === 0; break;\n }\n if (invert) {\n modules[y][x] = !modules[y][x];\n }\n }\n }\n}\n\n// \u2500\u2500 Mask penalty scoring (rules N1\u2013N4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction computePenalty(modules: boolean[][]): number {\n const size = modules.length;\n let penalty = 0;\n\n // N1: runs of \u22655 same-colour modules in a row/column.\n for (let y = 0; y < size; y++) {\n let runColor = false;\n let runLength = 0;\n for (let x = 0; x < size; x++) {\n if (x === 0 || modules[y][x] !== runColor) {\n runColor = modules[y][x];\n runLength = 1;\n } else {\n runLength++;\n if (runLength === 5) {\n penalty += 3;\n } else if (runLength > 5) {\n penalty += 1;\n }\n }\n }\n }\n for (let x = 0; x < size; x++) {\n let runColor = false;\n let runLength = 0;\n for (let y = 0; y < size; y++) {\n if (y === 0 || modules[y][x] !== runColor) {\n runColor = modules[y][x];\n runLength = 1;\n } else {\n runLength++;\n if (runLength === 5) {\n penalty += 3;\n } else if (runLength > 5) {\n penalty += 1;\n }\n }\n }\n }\n\n // N2: 2\u00D72 blocks of the same colour.\n for (let y = 0; y < size - 1; y++) {\n for (let x = 0; x < size - 1; x++) {\n const c = modules[y][x];\n if (c === modules[y][x + 1] && c === modules[y + 1][x] && c === modules[y + 1][x + 1]) {\n penalty += 3;\n }\n }\n }\n\n // N3: finder-like 1:1:3:1:1 patterns with 4-module light flank.\n const hasFinderPattern = (line: boolean[], start: number): number => {\n const core = [true, false, true, true, true, false, true];\n const matchesCore = core.every((value, index) => line[start + index] === value);\n if (!matchesCore) {\n return 0;\n }\n const lightBefore = start >= 4 && line.slice(start - 4, start).every((v) => !v);\n const lightAfter = start + 11 <= line.length && line.slice(start + 7, start + 11).every((v) => !v);\n return (lightBefore ? 40 : 0) + (lightAfter ? 40 : 0);\n };\n\n for (let y = 0; y < size; y++) {\n const row = modules[y];\n const column = modules.map((r) => r[y]);\n for (let x = 0; x + 7 <= size; x++) {\n penalty += hasFinderPattern(row, x);\n penalty += hasFinderPattern(column, x);\n }\n }\n\n // N4: dark-module proportion deviation from 50%, in 5% steps.\n let dark = 0;\n for (const row of modules) {\n for (const module of row) {\n if (module) {\n dark++;\n }\n }\n }\n const total = size * size;\n const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;\n penalty += k * 10;\n\n return penalty;\n}\n\n// \u2500\u2500 SVG rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Options for {@link qrToSvg}. */\nexport interface QrSvgOptions {\n /** Dark module colour. @default '#000000' */\n dark?: string;\n\n /** Light/background colour; `'transparent'` is allowed. @default '#ffffff' */\n light?: string;\n\n /** Quiet-zone width in modules on each side. @default 2 */\n quietZone?: number;\n}\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\n/**\n * Renders an encoded symbol as a crisp, scalable `<svg>` element. One\n * `<path>` carries all dark modules so the output stays compact.\n *\n * Built with `createElementNS`/`setAttribute` rather than markup strings so\n * caller-supplied colours can never be interpreted as HTML (CodeQL\n * js/html-constructed-from-input). Append the returned element directly;\n * never serialize it back through `innerHTML`.\n */\nexport function qrToSvg(qr: QrCode, options: QrSvgOptions = {}): SVGSVGElement {\n const dark = options.dark ?? '#000000';\n const light = options.light ?? '#ffffff';\n const quietZone = options.quietZone ?? 2;\n const dimension = qr.size + quietZone * 2;\n\n let path = '';\n for (let y = 0; y < qr.size; y++) {\n for (let x = 0; x < qr.size; x++) {\n if (qr.modules[y][x]) {\n path += `M${x + quietZone} ${y + quietZone}h1v1h-1z`;\n }\n }\n }\n\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('viewBox', `0 0 ${dimension} ${dimension}`);\n svg.setAttribute('shape-rendering', 'crispEdges');\n svg.setAttribute('role', 'img');\n\n const rect = document.createElementNS(SVG_NS, 'rect');\n rect.setAttribute('width', String(dimension));\n rect.setAttribute('height', String(dimension));\n rect.setAttribute('fill', light);\n svg.appendChild(rect);\n\n const modules = document.createElementNS(SVG_NS, 'path');\n modules.setAttribute('d', path);\n modules.setAttribute('fill', dark);\n svg.appendChild(modules);\n\n return svg;\n}\n", "/**\n * Wallet discovery via the `/.well-known/enbox-connect` document.\n *\n * Shared by the connect modal (relay discovery + custom-URL validation)\n * and exported for dapps rolling their own wallet selection UI.\n *\n * @module\n */\n\n/** Path of the wallet's connect discovery document, relative to its origin. */\nexport const WALLET_WELL_KNOWN_PATH = '/.well-known/enbox-connect';\n\n/** Timeout applied to the well-known validation fetch. */\nconst WELL_KNOWN_FETCH_TIMEOUT_MS = 6_000;\n\n/** The wallet's `/.well-known/enbox-connect` discovery document. */\nexport interface WalletWellKnownDocument {\n /** Base URL of the relay that brokers this wallet's remote connects. */\n connectServerUrl: string;\n}\n\n/**\n * Fetch a wallet's `/.well-known/enbox-connect` discovery document.\n *\n * Resolves the parsed document when it is reachable and names a\n * `connectServerUrl`; resolves `undefined` for unreachable origins, non-2xx\n * responses, CORS failures, and malformed documents.\n */\nexport async function fetchWalletWellKnown(origin: string): Promise<WalletWellKnownDocument | undefined> {\n try {\n const wellKnownUrl = new URL(WALLET_WELL_KNOWN_PATH, origin).toString();\n const response = await fetch(wellKnownUrl, { signal: AbortSignal.timeout(WELL_KNOWN_FETCH_TIMEOUT_MS) });\n if (!response.ok) {\n return undefined;\n }\n\n const payload = await response.json() as { connectServerUrl?: unknown } | null;\n if (typeof payload?.connectServerUrl !== 'string') {\n return undefined;\n }\n return { connectServerUrl: payload.connectServerUrl };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Fetch a wallet's `/.well-known/enbox-connect` discovery document to confirm\n * the origin hosts an Enbox-compatible wallet.\n *\n * Resolves `true` only when the document is reachable and names a\n * `connectServerUrl`. Unreachable origins, non-2xx responses, CORS failures,\n * and malformed documents resolve `false`.\n */\nexport async function probeWalletWellKnown(origin: string): Promise<boolean> {\n return (await fetchWalletWellKnown(origin)) !== undefined;\n}\n", "/**\n * Relay connect runner \u2014 the dapp side of the QR/deep-link connect flow,\n * with interactive PIN retry.\n *\n * This mirrors the `@enbox/connect` kernel `ConnectClient` step-for-step and\n * is composed entirely from the kernel's exported primitives (`sealRequest`,\n * `openResponse`, `RelayClientTransport`); no cryptography is reimplemented\n * here. It exists as a separate orchestrator for one reason the kernel\n * client cannot express today: **PIN retry against the delivered response**.\n * `ConnectClient` collects the PIN once and opens the response once, so a\n * mistyped code fails the whole handshake \u2014 the wallet user would have to\n * scan and approve again. The connect modal instead keeps the sealed\n * response and re-runs `openResponse` per attempt, which is safe because\n * opening is a pure decrypt-and-verify step.\n *\n * If the kernel later grows a PIN-attempts seam, this module collapses into\n * `ConnectClient` usage.\n *\n * @module\n */\n\nimport type { Jwk } from '@enbox/crypto';\nimport type {\n ConnectClientMetadata,\n ConnectPermissionRequest,\n ConnectRequest,\n ConnectResult,\n WalletUriHandoff,\n} from '@enbox/connect';\n\nimport { DidJwk } from '@enbox/dids';\nimport { X25519 } from '@enbox/crypto';\nimport {\n CONNECT_DENIED_TOKEN,\n openResponse,\n randomToken,\n RelayClientTransport,\n sealRequest,\n} from '@enbox/connect';\n\n/** Maximum interactive PIN attempts before the handshake fails. */\nexport const MAX_PIN_ATTEMPTS = 6;\n\n/** Thrown internally when a relay handshake is cancelled by the UI. */\nexport class RelayConnectCancelledError extends Error {\n constructor() {\n super('[@enbox/browser] Relay connect cancelled.');\n this.name = 'RelayConnectCancelledError';\n }\n}\n\n/** Options for {@link runRelayConnect}. */\nexport interface RelayConnectOptions {\n /** Relay base URL (the wallet's `connectServerUrl`). */\n connectServerUrl: string;\n\n /** Wallet URI the request pointer is attached to (QR / deep-link target). */\n walletUri: string;\n\n /** The user-friendly name of the app, shown in the wallet consent UI. */\n appName: string;\n\n /** Optional icon URL for the app, shown in the wallet consent UI. */\n appIcon?: string;\n\n /** Optional client/environment metadata for wallet session display. */\n clientMetadata?: ConnectClientMetadata;\n\n /** DWN protocols and permission scopes being requested. */\n permissionRequests: ConnectPermissionRequest[];\n\n /** Total milliseconds to poll the relay for a wallet response. */\n timeoutMs?: number;\n\n /** Milliseconds between relay polling attempts. */\n pollIntervalMs?: number;\n\n /**\n * Receives the wallet URI handoff (with the request pointer TTL) as soon\n * as the request is delivered \u2014 render it as a QR code or deep link.\n */\n onWalletUriReady: (handoff: WalletUriHandoff) => void;\n\n /**\n * Collects one PIN attempt from the user. Called again (with the attempt\n * number, 1-based, and the previous failure) after a wrong code, up to\n * {@link MAX_PIN_ATTEMPTS} times.\n */\n requestPin: (attempt: number, previousError?: Error) => Promise<string>;\n\n /**\n * Cancellation signal: when it settles, polling stops and the handshake\n * rejects with {@link RelayConnectCancelledError}.\n */\n cancelled?: Promise<never> | undefined;\n\n /**\n * Invoked once when the relay reports the wallet has claimed (fetched)\n * the pushed request \u2014 the app can show \"phone connected\" progress.\n */\n onClaimed?: () => void;\n\n /** Transport factory override (tests). */\n createTransport?: (options: {\n connectServerUrl: string;\n walletUri: string;\n timeoutMs?: number;\n pollIntervalMs?: number;\n onClaimed?: () => void;\n }) => Pick<RelayClientTransport, 'requestProfile' | 'deliverRequest' | 'awaitResponse' | 'requiresPin'>\n & Partial<Pick<RelayClientTransport, 'confirmComplete'>>;\n}\n\n/**\n * Sleep used between relay polls that ends early when the page returns to\n * the foreground. Browsers throttle \u2014 and mobile browsers freeze \u2014 timers in\n * background tabs, so a plain interval sleep can leave the user staring at a\n * stale stage after approving in the wallet tab; cutting the sleep short on\n * `visibilitychange` makes the next poll (and with it the pairing-code\n * prompt) land the moment they switch back. Falls back to a plain sleep\n * outside DOM environments.\n */\nexport function visibilityAwareSleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n if (typeof document === 'undefined') {\n setTimeout(resolve, ms);\n return;\n }\n\n const finish = (): void => {\n clearTimeout(timer);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n resolve();\n };\n const onVisibilityChange = (): void => {\n if (document.visibilityState === 'visible') {\n finish();\n }\n };\n const timer = setTimeout(finish, ms);\n document.addEventListener('visibilitychange', onVisibilityChange);\n });\n}\n\n/**\n * Runs one relay-mediated connect handshake end-to-end and returns the\n * delegated credentials, or `undefined` when the user denied in the wallet.\n */\nexport async function runRelayConnect(options: RelayConnectOptions): Promise<ConnectResult | undefined> {\n const createTransport = options.createTransport\n ?? ((transportOptions): RelayClientTransport => new RelayClientTransport({\n ...transportOptions,\n sleep: visibilityAwareSleep,\n }));\n\n const transport = createTransport({\n connectServerUrl : options.connectServerUrl,\n walletUri : options.walletUri,\n timeoutMs : options.timeoutMs,\n pollIntervalMs : options.pollIntervalMs,\n onClaimed : options.onClaimed,\n });\n\n // Ephemeral client DID for request signing and response addressing, and a\n // fresh X25519 pair the wallet seals the response to \u2014 same shape as the\n // kernel `ConnectClient`.\n const clientDid = await DidJwk.create();\n const responsePrivateKey = await X25519.generateKey();\n const responsePublicKey: Jwk = { kty: 'OKP', crv: 'X25519', x: responsePrivateKey.x };\n\n const nonce = randomToken();\n const state = randomToken();\n\n const profile = await transport.requestProfile(state);\n\n const request: ConnectRequest = {\n clientDid : clientDid.uri,\n appName : options.appName,\n appIcon : options.appIcon,\n clientMetadata : options.clientMetadata,\n permissionRequests : options.permissionRequests,\n supportedDidMethods : ['did:dht', 'did:jwk'],\n nonce,\n state,\n responseKey : responsePublicKey,\n reply : profile.reply,\n };\n\n const requestJwe = await sealRequest({ request, signer: clientDid, encryption: profile.encryption });\n\n const handoff = await transport.deliverRequest(requestJwe);\n if (handoff !== undefined) {\n options.onWalletUriReady(handoff);\n }\n\n const race = options.cancelled === undefined\n ? transport.awaitResponse()\n : Promise.race([transport.awaitResponse(), options.cancelled]);\n\n const responseCiphertext = await race;\n if (responseCiphertext === CONNECT_DENIED_TOKEN) {\n return undefined;\n }\n\n // Interactive PIN loop: opening is a pure decrypt-and-verify step, so a\n // wrong code costs one more attempt, not a whole new wallet approval.\n // Errors raised by the kernel's value checks carry a 'Connect:' prefix and\n // indicate a protocol violation, not a mistyped code \u2014 those fail closed.\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= MAX_PIN_ATTEMPTS; attempt++) {\n const pin = await (options.cancelled === undefined\n ? options.requestPin(attempt, lastError)\n : Promise.race([options.requestPin(attempt, lastError), options.cancelled]));\n\n try {\n const response = await openResponse({\n jwe : responseCiphertext,\n recipientPrivateKey : responsePrivateKey,\n expected : { clientDid: clientDid.uri, nonce, state },\n pin,\n });\n\n if (response.delegatePortableDid === undefined) {\n throw new Error('Connect: wallet response omitted `delegatePortableDid`.');\n }\n\n // Best-effort completion signal so the wallet can flip its pairing\n // screen to a confirmed \"connected\" state instead of leaving the user\n // to dismiss it blind. Fire-and-forget \u2014 mirrors the kernel client.\n void transport.confirmComplete?.().catch((): undefined => undefined);\n\n return {\n delegatePortableDid : response.delegatePortableDid,\n delegateGrants : response.delegateGrants,\n connectedDid : response.providerDid,\n sessionRevocations : response.sessionRevocations,\n };\n } catch (error) {\n const failure = error instanceof Error ? error : new Error(String(error));\n if (failure.message.startsWith('Connect:')) {\n // Structural/value-check failure \u2014 retrying the PIN cannot help.\n throw failure;\n }\n lastError = failure;\n }\n }\n\n throw new Error(`[@enbox/browser] The pairing code did not match after ${MAX_PIN_ATTEMPTS} attempts.`);\n}\n", "/**\n * Browser connect handler for `@enbox/auth`.\n *\n * Implements the {@link ConnectHandler} interface using browser-native\n * DWeb Connect (popup + postMessage) with a wallet selector modal.\n *\n * @module\n */\n\nimport type { ConnectPermissionRequest } from '@enbox/connect';\nimport type { ConnectHandler, ConnectResult } from '@enbox/auth';\n\nimport { runConnectModal } from './ui/connect-modal.js';\n\nimport type { ConnectMethod, ConnectModalTheme } from './ui/connect-modal.js';\n\n/** A wallet entry shown in the wallet selector modal. */\nexport interface WalletOption {\n /** Display name (e.g. \"Enbox\"). */\n name: string;\n\n /** Base URL of the wallet app (e.g. \"https://enbox-wallet.pages.dev\"). */\n url: string;\n\n /** Optional icon URL. If omitted, the wallet's favicon is used. */\n icon?: string;\n\n /** Short description shown below the wallet name in the selector. */\n description?: string;\n}\n\n/** Default wallets shown in the selector when no overrides are provided. */\nexport const DEFAULT_WALLETS: WalletOption[] = [\n {\n name : 'Enbox',\n url : 'https://enbox-wallet.pages.dev',\n description : 'Manage your digital identity and data',\n },\n {\n name : 'Prism',\n url : 'https://prism-wallet.pages.dev',\n description : 'A clear view into your digital identity',\n },\n {\n name : 'Matcha',\n url : 'https://matcha-wallet.pages.dev',\n description : 'A fresh approach to digital identity',\n },\n {\n name : 'Onyx',\n url : 'https://onyx-wallet.pages.dev',\n description : 'A refined home for your digital identity',\n },\n {\n name : 'Taffy',\n url : 'https://taffy-wallet.pages.dev',\n description : 'A playful take on your digital identity',\n },\n {\n name : 'Astoria',\n url : 'https://astoria-wallet.pages.dev',\n description : 'A grand home for your digital identity',\n },\n];\n\n/** Options for creating a BrowserConnectHandler. */\nexport interface BrowserConnectHandlerOptions {\n /**\n * Known wallets shown in the wallet selector modal.\n * If omitted, {@link DEFAULT_WALLETS} is used.\n */\n wallets?: WalletOption[];\n\n /**\n * Explicit wallet URL. If provided, the wallet selector is skipped\n * and this URL is used directly.\n */\n walletUrl?: string;\n\n /**\n * Timeout in milliseconds for the wallet popup flow.\n * @default 300_000 (5 minutes)\n */\n timeout?: number;\n\n /**\n * Display name of the requesting application.\n * Shown in the wallet's permission consent screen.\n */\n appName?: string;\n\n /**\n * Icon URL of the requesting application.\n * Shown alongside the app name in the wallet's consent screen.\n * Defaults to `${window.location.origin}/favicon.ico` if omitted.\n */\n appIcon?: string;\n\n /**\n * Preferred connect method on open: `'phone'` (QR / deep link via the\n * relay) or `'browser'` (wallet popup on this device). Overrides the\n * remembered choice.\n * @default 'phone'\n */\n preferredMethod?: ConnectMethod;\n\n /**\n * Remember the successful method + wallet in localStorage and pre-shape\n * the next connect session accordingly.\n * @default true\n */\n rememberChoice?: boolean;\n\n /**\n * Relay base URL override for the phone path. When omitted, each wallet's\n * `connectServerUrl` is discovered from its `/.well-known/enbox-connect`\n * document.\n */\n connectServerUrl?: string;\n\n /**\n * Path appended to the wallet origin to form the phone path's QR /\n * deep-link target.\n * @default '/connect/app'\n */\n relayWalletPath?: string;\n\n /**\n * Color scheme for the connect modal. By default it follows the\n * visitor's system light/dark appearance; apps can force an appearance\n * and/or override palette tokens (accent, surfaces, text) per scheme to\n * match their brand.\n */\n theme?: ConnectModalTheme;\n}\n\n/**\n * Create a browser-native connect handler over the connect modal.\n *\n * The modal owns the whole session on one surface: the phone path (a QR /\n * deep link over the relay, with pairing-code entry) is the default, the\n * in-browser wallet popup is the alternate, and the wallet catalog plus\n * custom-URL entry live in a disclosure. It resolves with the delegate\n * credentials on success and `undefined` when the user denies.\n *\n * @example\n * ```ts\n * import { AuthManager, BrowserConnectHandler } from '@enbox/browser';\n *\n * const auth = await AuthManager.create({\n * connectHandler: BrowserConnectHandler({\n * appName: 'My Dapp',\n * }),\n * });\n *\n * const session = await auth.connect({ protocols: [NotesProtocol] });\n * ```\n */\nexport function BrowserConnectHandler(\n options: BrowserConnectHandlerOptions = {},\n): ConnectHandler {\n const {\n wallets = DEFAULT_WALLETS,\n walletUrl,\n timeout,\n appName,\n appIcon,\n preferredMethod,\n rememberChoice,\n connectServerUrl,\n relayWalletPath,\n theme,\n } = options;\n\n return {\n async requestAccess(params: {\n permissionRequests: ConnectPermissionRequest[];\n }): Promise<ConnectResult | undefined> {\n return runConnectModal({\n wallets,\n walletUrl,\n preferredMethod,\n rememberChoice,\n appName,\n appIcon : appIcon ?? `${window.location.origin}/favicon.ico`,\n connectServerUrl,\n relayWalletPath,\n timeout,\n theme,\n permissionRequests : params.permissionRequests,\n });\n },\n };\n}\n", "/**\n * DWeb Connect wallet transport \u2014 the wallet side of the popup/postMessage\n * connect flow, exported for wallet apps (e.g. the Enbox web wallet).\n *\n * A wallet's `/dweb-connect` page creates one transport per session:\n *\n * 1. `create()` generates a fresh ephemeral X25519 key pair and emits the\n * `loaded` beacon (public key + wallet origin) to the opener window with a\n * pinned `targetOrigin`.\n * 2. `awaitRequest()` receives the sealed request ciphertext and opens it via\n * the `@enbox/connect` kernel (`ConnectProvider.openRequest`), which\n * value-checks the `apv` origin binding against this wallet's origin.\n * 3. After the consent ceremony, the wallet posts the sealed response JWE via\n * `sendResponse()` \u2014 or the deny token via `deny()` \u2014 back to the opener,\n * again with a pinned `targetOrigin`. `sendResponseAwaitingAck()` does the\n * same but stays alive briefly for the dapp's completion ack, so the\n * wallet can show a confirmed \"connected\" state before closing itself.\n *\n * The dapp origin is never assumed: it is taken from an explicit option or\n * derived from `document.referrer`, and `create()` fails when neither is\n * available. `'*'` is never used as a `targetOrigin`.\n *\n * @module\n */\n\nimport type { ConnectRequest } from '@enbox/connect';\nimport type { Jwk } from '@enbox/crypto';\n\nimport { X25519 } from '@enbox/crypto';\nimport { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';\n\nimport {\n DWEB_CONNECT_ACK_MESSAGE_TYPE,\n DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n DWEB_CONNECT_REQUEST_MESSAGE_TYPE,\n DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n getTrustedMessage,\n} from './dweb-connect-messages.js';\n\n/** Default budget for awaiting the dapp's sealed request. */\nconst DEFAULT_REQUEST_TIMEOUT_MS = 300_000;\n\n/** Default budget for awaiting the dapp's completion ack after a response. */\nconst DEFAULT_ACK_TIMEOUT_MS = 5_000;\n\n/** Options for creating a {@link WalletPostMessageTransport}. */\nexport type WalletPostMessageTransportOptions = {\n /**\n * Origin of the dapp that opened this wallet popup. When omitted, it is\n * derived from `document.referrer`; creation fails when neither is\n * available \u2014 the transport never falls back to `'*'`.\n */\n dappOrigin?: string;\n\n /**\n * The dapp window to exchange messages with.\n * @default window.opener\n */\n dappWindow?: Window;\n\n /**\n * Budget in milliseconds for awaiting the dapp's sealed request.\n * @default 300_000 (5 minutes)\n */\n timeoutMs?: number;\n};\n\n/**\n * Wallet-side postMessage transport for the DWeb Connect popup flow.\n *\n * Security properties:\n * - `targetOrigin` of every outbound `postMessage` (beacon and response) is\n * pinned to the dapp origin \u2014 never `'*'`.\n * - Inbound messages are dropped unless `event.origin` equals the pinned dapp\n * origin AND `event.source` is the dapp window.\n * - The ephemeral X25519 private key never leaves the transport; the request\n * JWE is opened by the kernel with the `apv` header value-checked against\n * this wallet's own origin.\n */\nexport class WalletPostMessageTransport {\n private readonly _dappOrigin: string;\n private readonly _dappWindow: Window;\n private readonly _recipientPrivateKey: Jwk;\n\n private _requestReceived = false;\n private _timeoutId?: ReturnType<typeof setTimeout>;\n private _messageListener?: (event: MessageEvent) => void;\n private _resolveAck?: (acked: boolean) => void;\n\n private readonly _requestPromise: Promise<ConnectRequest>;\n private _resolveRequest?: (request: ConnectRequest) => void;\n private _rejectRequest?: (error: Error) => void;\n\n private constructor(params: { dappOrigin: string; dappWindow: Window; recipientPrivateKey: Jwk; timeoutMs: number }) {\n this._dappOrigin = params.dappOrigin;\n this._dappWindow = params.dappWindow;\n this._recipientPrivateKey = params.recipientPrivateKey;\n\n this._requestPromise = new Promise<ConnectRequest>((resolve, reject): void => {\n this._resolveRequest = resolve;\n this._rejectRequest = reject;\n });\n // Mark early rejections (timeout before `awaitRequest()` is called) as\n // handled until the wallet attaches its own handlers.\n this._requestPromise.catch((): undefined => undefined);\n\n this._messageListener = (event: MessageEvent): void => { this.onMessage(event); };\n window.addEventListener('message', this._messageListener);\n\n this._timeoutId = setTimeout((): void => {\n this.close();\n this._rejectRequest?.(new Error('[@enbox/browser] Timed out waiting for the connect request from the dapp.'));\n }, params.timeoutMs);\n }\n\n /**\n * Creates the transport for one connect session: resolves and pins the dapp\n * origin, generates a fresh ephemeral X25519 key pair, starts listening for\n * the sealed request, and emits the `loaded` beacon to the dapp window.\n *\n * @throws If not in a browser, if no dapp window is available, or if the\n * dapp origin can neither be supplied nor derived from the referrer.\n */\n public static async create(options: WalletPostMessageTransportOptions = {}): Promise<WalletPostMessageTransport> {\n if (typeof window === 'undefined') {\n throw new Error('[@enbox/browser] WalletPostMessageTransport is only available in browser environments.');\n }\n\n const dappWindow = options.dappWindow ?? window.opener as Window | null;\n if (!dappWindow) {\n throw new Error('[@enbox/browser] No opener window: the DWeb Connect page must be opened as a popup by the dapp.');\n }\n\n const dappOrigin = resolveDappOrigin(options.dappOrigin);\n\n const recipientPrivateKey = await X25519.generateKey();\n const walletEpk: Jwk = { kty: 'OKP', crv: 'X25519', x: recipientPrivateKey.x };\n\n const transport = new WalletPostMessageTransport({\n dappOrigin,\n dappWindow,\n recipientPrivateKey,\n timeoutMs: options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,\n });\n\n // The listener is registered, so the beacon cannot race the request.\n dappWindow.postMessage({\n type : DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n walletEpk,\n walletOrigin : globalThis.location.origin,\n }, dappOrigin);\n\n return transport;\n }\n\n /** The pinned origin of the dapp this transport exchanges messages with. */\n public get dappOrigin(): string {\n return this._dappOrigin;\n }\n\n /**\n * Awaits the dapp's sealed request and opens it via the kernel: ECDH-ES\n * decryption with this session's ephemeral key, `apv` value-checked against\n * this wallet's origin, JWT signature verification, and payload shape\n * assertion. Rejects on timeout, on an unopenable request, or when the\n * request does not use the `post_message` reply mode.\n */\n public async awaitRequest(): Promise<ConnectRequest> {\n return await this._requestPromise;\n }\n\n /**\n * Posts the sealed response JWE (or the deny token) back to the dapp window\n * with the `targetOrigin` pinned to the dapp origin, then closes the\n * transport.\n *\n * @param idToken - The sealed response JWE, or the literal deny token.\n */\n public sendResponse(idToken: string): void {\n this._dappWindow.postMessage({\n type : DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n payload : idToken,\n }, this._dappOrigin);\n this.close();\n }\n\n /**\n * Posts the sealed response JWE back to the dapp like\n * {@link sendResponse}, then keeps the channel open briefly for the dapp's\n * completion ack \u2014 the signal that it opened the response successfully \u2014\n * before closing the transport.\n *\n * Lets the wallet's connect page show a confirmed \"connected\" state (and\n * close itself with confidence) instead of asking the user to dismiss the\n * screen blind. Dapps predating the ack simply never send one, so the\n * wallet should keep a manual dismiss affordance for the `false` case.\n *\n * @param idToken - The sealed response JWE.\n * @param options - The awaiting options.\n * @param options.timeoutMs - Ack budget in milliseconds; defaults to 5 s.\n * @returns Whether the dapp acknowledged completion within the budget.\n */\n public async sendResponseAwaitingAck(idToken: string, options: { timeoutMs?: number } = {}): Promise<boolean> {\n const ackPromise = new Promise<boolean>((resolve): void => {\n this._resolveAck = resolve;\n });\n\n this._dappWindow.postMessage({\n type : DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n payload : idToken,\n }, this._dappOrigin);\n\n const ackTimeoutId = setTimeout((): void => {\n this._resolveAck?.(false);\n }, options.timeoutMs ?? DEFAULT_ACK_TIMEOUT_MS);\n\n const acked = await ackPromise;\n clearTimeout(ackTimeoutId);\n this._resolveAck = undefined;\n this.close();\n return acked;\n }\n\n /** Posts the deny token back to the dapp \u2014 the user rejected the request. */\n public deny(): void {\n this.sendResponse(CONNECT_DENIED_TOKEN);\n }\n\n /** Stops listening and releases the session's timers. Idempotent. */\n public close(): void {\n clearTimeout(this._timeoutId);\n if (this._messageListener !== undefined) {\n window.removeEventListener('message', this._messageListener);\n this._messageListener = undefined;\n }\n }\n\n private onMessage(event: MessageEvent): void {\n const message = getTrustedMessage(event, this._dappOrigin, this._dappWindow);\n if (message === undefined) { return; }\n\n if (message.type === DWEB_CONNECT_ACK_MESSAGE_TYPE) {\n this._resolveAck?.(true);\n return;\n }\n\n if (message.type !== DWEB_CONNECT_REQUEST_MESSAGE_TYPE || this._requestReceived) { return; }\n this._requestReceived = true;\n\n if (typeof message.jwe !== 'string') {\n this.settleRequest(new Error('[@enbox/browser] Connect request message did not carry a ciphertext payload.'));\n return;\n }\n\n void this.openRequest(message.jwe);\n }\n\n private async openRequest(jwe: string): Promise<void> {\n try {\n const request = await ConnectProvider.openRequest({\n jwe,\n decryption: {\n mode : 'ecdh-es',\n recipientPrivateKey : this._recipientPrivateKey,\n walletOrigin : globalThis.location.origin,\n },\n });\n\n if (request.reply.mode !== 'post_message') {\n this.settleRequest(new Error('[@enbox/browser] Connect request over the popup channel must use the `post_message` reply mode.'));\n return;\n }\n\n this.settleRequest(request);\n } catch (error) {\n this.settleRequest(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n private settleRequest(outcome: ConnectRequest | Error): void {\n clearTimeout(this._timeoutId);\n if (outcome instanceof Error) {\n this.close();\n this._rejectRequest?.(outcome);\n return;\n }\n this._resolveRequest?.(outcome);\n }\n}\n\n/**\n * Resolves the dapp origin to pin: the explicit option when provided,\n * otherwise the origin of `document.referrer`. Never falls back to `'*'`.\n */\nfunction resolveDappOrigin(explicitOrigin: string | undefined): string {\n if (explicitOrigin !== undefined) {\n return new URL(explicitOrigin).origin;\n }\n\n if (document.referrer) {\n return new URL(document.referrer).origin;\n }\n\n throw new Error(\n '[@enbox/browser] Unable to determine the dapp origin: no `dappOrigin` option was provided and `document.referrer` is empty.'\n );\n}\n"],
5
- "mappings": "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AA;AAAA,gBAgBVC,EAAW;AAAA;AAAA;AAAA,uCAGYD,EAAY;AAAA;AAAA,sCAEbC,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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",
6
- "names": ["Enbox", "defineProtocol", "repository", "AuthManager", "AuthSession", "normalizeProtocolRequests", "WalletConnect", "CONNECT_DENIED_TOKEN", "ConnectProvider", "DidDht", "DidWeb", "UniversalResolver", "parseDrlUrl", "url", "idx", "prefix", "rest", "slashIdx", "didResolver", "UniversalResolver", "DidDht", "DidWeb", "httpToHttpsRegex", "trailingSlashRegex", "DRL_CACHE_NAME", "getDwnEndpoints", "did", "didDocument", "endpoints", "service", "url", "openDrlCache", "handleEvent", "event", "path", "options", "drl", "responseCache", "cachedResponse", "match", "cacheTime", "fetchResource", "response", "error", "lastError", "endpoint", "cacheResponse", "cache", "clonedResponse", "headers", "modifiedResponse", "installWorker", "workerSelf", "parsed", "parseDrlUrl", "installUrl", "loaderStyles", "tabContent", "elementsInjected", "overlayElement", "styleElement", "injectElements", "cancelNavigation", "removeElements", "activeNavigation", "linkFeaturesActive", "clickHandler", "pointerdownHandler", "addLinkFeatures", "anchor", "href", "openAsTab", "tab", "target", "resetContextMenuTarget", "contextMenuTarget", "removeLinkFeatures", "r", "activatePolyfills", "deactivatePolyfills", "clearDrlCache", "ConnectClient", "buildWalletIcon", "wallet", "wrap", "badge", "sources", "iconCandidates", "img", "index", "origin", "assertX25519PublicJwk", "CONNECT_DENIED_TOKEN", "ConnectClient", "DWEB_CONNECT_PATH", "DWEB_CONNECT_LOADED_MESSAGE_TYPE", "DWEB_CONNECT_REQUEST_MESSAGE_TYPE", "DWEB_CONNECT_RESPONSE_MESSAGE_TYPE", "DWEB_CONNECT_ACK_MESSAGE_TYPE", "getTrustedMessage", "event", "expectedOrigin", "expectedSource", "data", "DEFAULT_TIMEOUT_MS", "CLOSED_POLL_INTERVAL_MS", "CLOSED_RESPONSE_GRACE_MS", "POPUP_WINDOW_NAME", "POPUP_WIDTH", "POPUP_HEIGHT", "popupWindowFeatures", "base", "openerWidth", "openerHeight", "left", "top", "assertBrowserEnvironment", "PopupWindowClosedError", "PopupClientTransport", "options", "popupUrl", "DWEB_CONNECT_PATH", "popup", "resolve", "reject", "event", "state", "jwe", "DWEB_CONNECT_REQUEST_MESSAGE_TYPE", "DWEB_CONNECT_ACK_MESSAGE_TYPE", "message", "getTrustedMessage", "DWEB_CONNECT_LOADED_MESSAGE_TYPE", "DWEB_CONNECT_RESPONSE_MESSAGE_TYPE", "walletEpk", "assertX25519PublicJwk", "CONNECT_DENIED_TOKEN", "error", "collectBrowserClientMetadata", "resolvedOptions", "languages", "language", "connectViaPopup", "transport", "client", "ConnectClient", "ECC_PER_BLOCK", "NUM_BLOCKS", "TOTAL_CODEWORDS", "FORMAT_ECL_M", "MAX_VERSION", "dataCodewords", "version", "encodeQr", "text", "forcedMask", "data", "candidate", "capacityBits", "bits", "pushBits", "value", "length", "i", "byte", "padBytes", "codewords", "allCodewords", "buildInterleavedCodewords", "size", "modules", "isFunction", "drawFunctionPatterns", "drawCodewords", "mask", "bestPenalty", "applyMask", "drawFormatBits", "penalty", "computePenalty", "numBlocks", "eccLen", "totalCodewords", "numShortBlocks", "shortBlockLen", "blocks", "eccBlocks", "rsDivisor", "reedSolomonDivisor", "offset", "dataLen", "block", "reedSolomonRemainder", "result", "index", "maxDataLen", "b", "gfMultiply", "x", "y", "z", "degree", "root", "j", "divisor", "factor", "ALIGNMENT_POSITIONS", "setFunctionModule", "dark", "drawFinderPattern", "positions", "drawAlignmentPattern", "drawVersionBits", "cx", "cy", "dy", "dx", "distance", "rem", "bit", "a", "bitIndex", "right", "vertical", "invert", "runColor", "runLength", "c", "hasFinderPattern", "line", "start", "lightBefore", "v", "lightAfter", "row", "column", "r", "module", "total", "k", "SVG_NS", "qrToSvg", "qr", "options", "light", "quietZone", "dimension", "path", "svg", "rect", "WALLET_WELL_KNOWN_PATH", "fetchWalletWellKnown", "origin", "wellKnownUrl", "WALLET_WELL_KNOWN_PATH", "response", "payload", "probeWalletWellKnown", "DidJwk", "X25519", "CONNECT_DENIED_TOKEN", "openResponse", "randomToken", "RelayClientTransport", "sealRequest", "MAX_PIN_ATTEMPTS", "RelayConnectCancelledError", "visibilityAwareSleep", "ms", "resolve", "finish", "timer", "onVisibilityChange", "runRelayConnect", "options", "transport", "transportOptions", "clientDid", "responsePrivateKey", "responsePublicKey", "nonce", "state", "profile", "request", "requestJwe", "handoff", "responseCiphertext", "lastError", "attempt", "pin", "response", "error", "failure", "LAST_CHOICE_STORAGE_KEY", "REMINT_SAFETY_MS", "REMINT_MIN_MS", "PIN_LENGTH", "WALLET_SEARCH_THRESHOLD", "WALLET_ROW_SIZE", "PALETTE_TOKENS", "discoverWalletConnectServerUrl", "walletOrigin", "fetchWalletWellKnown", "runPopupConnect", "options", "transport", "PopupClientTransport", "ConnectClient", "collectBrowserClientMetadata", "defaultIsMobile", "defaultDeps", "runRelayConnect", "probeWalletWellKnown", "readLastChoice", "storage", "raw", "parsed", "writeLastChoice", "choice", "createRelaySession", "cancel", "session", "cancelled", "_", "reject", "RelayConnectCancelledError", "runConnectModal", "deps", "wallets", "dedupeWalletsByUrl", "rememberChoice", "appName", "relayWalletPath", "isMobile", "lastChoice", "lockedWallet", "walletUrl", "walletInCatalog", "method", "resolve", "host", "shadow", "style", "MODAL_STYLES", "overlay", "modal", "theme", "appearance", "systemDark", "hasPaletteOverrides", "applyPaletteTokens", "scheme", "palette", "key", "value", "onSchemeChange", "settled", "relaySession", "remintTimer", "remintAt", "popupBusy", "pinResolve", "discoveryCache", "rowWallets", "walletByUrl", "url", "wallet", "hostnameOf", "composeWalletRow", "selected", "selectWallet", "renderFooter", "startMethod", "cleanup", "clearRemint", "onKeydown", "onVisibilityReturn", "settle", "settler", "succeed", "result", "renderConnected", "cancelModal", "buildHeader", "stage", "footer", "setStage", "nodes", "renderBusy", "message", "el", "morphToAway", "walletName", "renderAway", "buildHandoffLink", "handoff", "className", "link", "renderQr", "qrLink", "qrToSvg", "encodeQr", "logo", "buildWalletIcon", "stageLinkButton", "startPhone", "renderClaimed", "pulse", "renderPin", "attempt", "previousError", "resolvePin", "boxes", "inputs", "i", "input", "submitIfComplete", "code", "resolveOnce", "index", "event", "digits", "digit", "digitIndex", "check", "renderDenied", "stageButton", "renderError", "error", "renderPhoneUnavailable", "startPopup", "popupSurface", "renderPopupPrompt", "renderPopupWaiting", "renderPopupInterrupted", "blocked", "switchMethod", "renderPopupFailure", "failure", "popupBlocked", "PopupWindowClosedError", "resolveConnectServerUrl", "origin", "cached", "remintNow", "scheduleRemint", "expiresInSeconds", "delay", "connectServerUrl", "next", "switcher", "buildWalletSwitcher", "row", "alt", "tile", "isSelected", "panel", "gridWallets", "shown", "more", "updateScrollHint", "label", "tiles", "empty", "search", "query", "visible", "match", "scrollWrap", "scroll", "grid", "overflowing", "atEnd", "tileName", "custom", "go", "urlError", "allowUnverified", "submitCustom", "valid", "e", "trapFocus", "candidate", "tag", "text", "node", "onClick", "button", "appIcon", "onCancel", "header", "identity", "icon", "title", "closeBtn", "focusables", "first", "last", "active", "LIGHT_TOKENS", "DARK_TOKENS", "DEFAULT_WALLETS", "BrowserConnectHandler", "options", "wallets", "walletUrl", "timeout", "appName", "appIcon", "preferredMethod", "rememberChoice", "connectServerUrl", "relayWalletPath", "theme", "params", "runConnectModal", "X25519", "CONNECT_DENIED_TOKEN", "ConnectProvider", "DEFAULT_REQUEST_TIMEOUT_MS", "DEFAULT_ACK_TIMEOUT_MS", "WalletPostMessageTransport", "_WalletPostMessageTransport", "params", "resolve", "reject", "event", "options", "dappWindow", "dappOrigin", "resolveDappOrigin", "recipientPrivateKey", "X25519", "walletEpk", "transport", "DWEB_CONNECT_LOADED_MESSAGE_TYPE", "idToken", "DWEB_CONNECT_RESPONSE_MESSAGE_TYPE", "ackPromise", "ackTimeoutId", "acked", "CONNECT_DENIED_TOKEN", "message", "getTrustedMessage", "DWEB_CONNECT_ACK_MESSAGE_TYPE", "DWEB_CONNECT_REQUEST_MESSAGE_TYPE", "jwe", "request", "ConnectProvider", "error", "outcome", "explicitOrigin", "TypedRecord", "BrowserStorage", "DwnInterface", "DateSort", "DwnInterfaceName", "DwnMethodName"]
4
+ "sourcesContent": ["/**\n * @enbox/browser \u2014 The Enbox browser SDK.\n *\n * For browser-based dapps, this is the only package you need to import.\n * It re-exports the high-level API from `@enbox/api`, the authentication\n * layer from `@enbox/auth`, and provides browser-specific connect handlers.\n *\n * @example Single-import dapp setup\n * ```ts\n * import {\n * Enbox, BrowserConnectHandler,\n * defineProtocol, repository,\n * } from '@enbox/browser';\n *\n * const { enbox, session } = await Enbox.connect({\n * connectHandler: BrowserConnectHandler({ appName: 'My App' }),\n * protocols: [MyProtocol],\n * });\n * ```\n *\n * For non-browser environments (Node.js, CLI, desktop), import from\n * `@enbox/api` and `@enbox/auth` directly instead.\n *\n * @packageDocumentation\n */\n\n// \u2500\u2500\u2500 Re-exports from @enbox/api \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The high-level Enbox API: DWN records, protocols, repositories.\n\nexport {\n Enbox,\n defineProtocol,\n repository,\n} from '@enbox/api';\n\nexport type {\n EnboxAnonymousOptions,\n EnboxConnectOptions,\n EnboxConnectResult,\n EnboxParams,\n EnboxSessionParams,\n} from '@enbox/api';\n\n// \u2500\u2500\u2500 Re-exports from @enbox/auth \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Authentication lifecycle, session management, connect handlers.\n\nexport {\n AuthManager,\n AuthSession,\n SESSION_EXPIRED_ERROR_CODE,\n SESSION_REVOKED_ERROR_CODE,\n computeConnectionStatus,\n isSessionExpiredError,\n isSessionInvalidError,\n normalizeProtocolRequests,\n WalletConnect,\n} from '@enbox/auth/browser';\n\nexport type {\n AuthEvent,\n AuthEventHandler,\n AuthManagerOptions,\n AuthState,\n ComputeConnectionStatusOptions,\n ConnectionMonitorOptions,\n ConnectionState,\n ConnectionStatus,\n ConnectionStatusGrant,\n ConnectHandler,\n ConnectOptions,\n ConnectResult,\n DisconnectOptions,\n GetConnectionStatusOptions,\n HandlerConnectOptions,\n ImportFromPortableOptions,\n VaultConnectOptions,\n Permission,\n PortableIdentity,\n ProtocolRequest,\n RefreshOptions,\n RegistrationOptions,\n StorageAdapter,\n SyncOption,\n WalletConnectOptions,\n} from '@enbox/auth/browser';\n\n// \u2500\u2500\u2500 Re-exports from @enbox/connect \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The connect kernel pieces wallet apps need alongside the popup\n// transports: opening/sealing envelopes and the deny token.\n\nexport { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';\nexport type { ConnectApproval, ConnectPermissionRequest, ConnectRequest, ConnectRequestType } from '@enbox/connect';\n\n// \u2500\u2500\u2500 Browser-specific exports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// DWeb Connect popup transports, wallet selector, DRL polyfills.\n\nexport * from './web-features.js';\nexport { BrowserConnectHandler, DEFAULT_WALLETS } from './browser-connect-handler.js';\nexport type { BrowserConnectHandlerOptions, WalletOption } from './browser-connect-handler.js';\nexport { connectViaPopup, PopupClientTransport, PopupWindowClosedError } from './dweb-connect-client.js';\nexport type { PopupClientTransportOptions, PopupConnectOptions } from './dweb-connect-client.js';\nexport { WalletPostMessageTransport } from './dweb-connect-wallet.js';\nexport type { WalletPostMessageTransportOptions } from './dweb-connect-wallet.js';\nexport {\n DWEB_CONNECT_ACK_MESSAGE_TYPE,\n DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n DWEB_CONNECT_PATH,\n DWEB_CONNECT_REQUEST_MESSAGE_TYPE,\n DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n} from './dweb-connect-messages.js';\nexport type {\n DWebConnectAckMessage,\n DWebConnectLoadedMessage,\n DWebConnectRequestMessage,\n DWebConnectResponseMessage,\n} from './dweb-connect-messages.js';\nexport { fetchWalletWellKnown, probeWalletWellKnown, WALLET_WELL_KNOWN_PATH } from './ui/wallet-well-known.js';\nexport type { WalletWellKnownDocument } from './ui/wallet-well-known.js';\nexport { discoverWalletConnectServerUrl, runConnectModal } from './ui/connect-modal.js';\nexport type { ConnectMethod, ConnectModalDeps, ConnectModalOptions, ConnectModalPalette, ConnectModalTheme } from './ui/connect-modal.js';\nexport { MAX_PIN_ATTEMPTS, RelayConnectCancelledError, runRelayConnect } from './relay-connect-runner.js';\nexport type { RelayConnectOptions } from './relay-connect-runner.js';\nexport { encodeQr, qrToSvg } from './ui/qr.js';\nexport type { QrCode, QrSvgOptions } from './ui/qr.js';\n\n// \u2500\u2500\u2500 Convenience re-exports for dapps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// So that most browser dapps only need `@enbox/browser` (plus\n// `@enbox/protocols` for shared protocol definitions). These surface the\n// symbols dapps most commonly reached into sibling packages for; anything\n// more specialized is still available by importing the underlying package\n// directly.\n\n// Typed record wrapper (from @enbox/api).\nexport { TypedRecord } from '@enbox/api';\n\n// Custom storage adapter + DWN registration provider-auth callback shapes\n// (from @enbox/auth).\nexport { BrowserStorage } from '@enbox/auth/browser';\nexport type { ProviderAuthParams, ProviderAuthResult } from '@enbox/auth/browser';\n\n// DWN interface enum for typing agent requests (from @enbox/agent).\nexport { DwnInterface } from '@enbox/agent';\n\n// Common DWN primitives for record queries, permission scopes, and protocol\n// typing (from @enbox/dwn-sdk-js).\nexport { DateSort, DwnInterfaceName, DwnMethodName } from '@enbox/dwn-sdk-js';\nexport type { ProtocolActionRule, ProtocolDefinition } from '@enbox/dwn-sdk-js';\n", "/*\n This file is run in dual environments to make installation of the Service Worker code easier.\n Be mindful that code placed in any open excution space may be evaluated multiple times in different contexts,\n so take care to gate additions to only activate code in the right env, such as a Service Worker scope or page window.\n*/\n\nimport type { DidMethodResolver } from '@enbox/dids';\n\nimport { DidDht, DidWeb, UniversalResolver } from '@enbox/dids';\n\n/**\n * Result returned by the `onCacheCheck` callback.\n * When returned, it signals that the response for the given DRL should be cached.\n */\nexport type CacheCheckResult = {\n /** Time-to-live for the cached DRL response, in milliseconds. */\n ttl?: number;\n};\n\n/**\n * Callback invoked to determine whether a DRL response should be cached and for how long.\n * Returning a truthy `CacheCheckResult` opts in to caching; returning a falsy value skips it.\n */\nexport type CacheCheckCallback = (\n event: FetchEvent | Event,\n drl: string,\n) => CacheCheckResult | undefined | null | Promise<CacheCheckResult | undefined | null>;\n\n/**\n * Configuration options for {@link activatePolyfills}.\n */\nexport type ActivatePolyfillsOptions = {\n /**\n * Path to the script to register as a Service Worker.\n * Falls back to `document.currentScript.src` or `import.meta.url`.\n *\n * **Required in strict CSP environments** where `new Function()` is blocked and `import.meta`\n * cannot be evaluated dynamically.\n */\n path?: string;\n /** Set to `false` to skip Service Worker installation. Defaults to `true`. */\n serviceWorker?: boolean;\n /** Set to `false` to skip injection of DRL loading-overlay styles. Defaults to `true`. */\n injectStyles?: boolean;\n /** Set to `false` to skip activation of DRL anchor/link click handling. Defaults to `true`. */\n links?: boolean;\n /** Callback to control per-request caching behaviour. */\n onCacheCheck?: CacheCheckCallback;\n /**\n * DID method resolvers to use for DRL resolution. Defaults to `[DidDht, DidWeb]`.\n * Pass a custom array to add or replace DID methods (e.g., `[DidDht, DidWeb, DidJwk]`).\n */\n didResolvers?: DidMethodResolver[];\n};\n\n/**\n * An `HTMLElement` that has a `src` property (e.g., `<img>`, `<video>`, `<audio>`).\n * Extended with `__src__` to stash the original DRL src during context-menu swaps.\n */\ninterface DrlMediaElement extends HTMLElement {\n src: string;\n __src__?: string;\n}\n\nlet didResolver = new UniversalResolver({ didResolvers: [DidDht, DidWeb] });\n\nimport { parseDrlUrl } from './drl-url-parser.js';\nexport { parseDrlUrl } from './drl-url-parser.js';\n\nconst httpToHttpsRegex = /^http:/;\nconst trailingSlashRegex = /\\/$/;\nconst DRL_CACHE_NAME = 'drl';\n\n/** @internal Exported for testing. Resolves DWN service endpoints from a DID. */\nexport async function getDwnEndpoints(did: string): Promise<string[]> {\n const { didDocument } = await didResolver.resolve(did);\n const endpoints = didDocument?.service?.find(\n (service) => service.type === 'DecentralizedWebNode'\n )?.serviceEndpoint;\n if (!endpoints) {return [];}\n return (Array.isArray(endpoints) ? endpoints : [endpoints]).filter(\n (url) => typeof url === 'string' && url.startsWith('http')\n );\n}\n\n/** Returns an open DRL cache, or `undefined` if the Cache API is unavailable. */\nasync function openDrlCache(): Promise<Cache | undefined> {\n if (typeof caches === 'undefined') {return undefined;}\n return caches.open(DRL_CACHE_NAME);\n}\n\n/** @internal Exported for testing. Handles a DRL fetch event. */\nexport async function handleEvent(\n event: FetchEvent, did: string, path: string, options?: ActivatePolyfillsOptions\n): Promise<Response> {\n const drl = event.request.url\n .replace(httpToHttpsRegex, 'https:')\n .replace(trailingSlashRegex, '');\n const responseCache = await openDrlCache();\n const cachedResponse = await responseCache?.match(drl);\n if (cachedResponse) {\n if (!navigator.onLine) {return cachedResponse;}\n const match = await options?.onCacheCheck?.(event, drl);\n if (match) {\n const cacheTime = cachedResponse.headers.get('dwn-cache-time');\n if (\n cacheTime &&\n Date.now() < Number(cacheTime) + (Number(match.ttl) || 0)\n ) {\n return cachedResponse;\n }\n }\n }\n try {\n if (path) {\n return await fetchResource(event, did, drl, path, responseCache, options);\n } else {\n const response = await didResolver.resolve(did);\n return new Response(JSON.stringify(response), {\n status : 200,\n headers : {\n 'Content-Type': 'application/json',\n },\n });\n }\n } catch (error) {\n if (error instanceof Response) {\n return error;\n }\n console.log(`Error in DID URL fetch: ${error}`);\n return new Response('DID URL fetch error', { status: 500 });\n }\n}\n\n/** @internal Exported for testing. Fetches a resource from DWN endpoints. */\nexport async function fetchResource(\n event: FetchEvent, did: string, drl: string, path: string,\n responseCache: Cache | undefined, options?: ActivatePolyfillsOptions\n): Promise<Response> {\n const endpoints = await getDwnEndpoints(did);\n if (!endpoints?.length) {\n throw new Response(\n 'DWeb Node resolution failed: no valid endpoints found.',\n { status: 530 }\n );\n }\n let lastError: Response | undefined;\n for (const endpoint of endpoints) {\n try {\n const url = `${endpoint.replace(trailingSlashRegex, '')}/${did}/${path}`;\n const response = await fetch(url, { headers: event.request.headers });\n if (response.ok) {\n const match = await options?.onCacheCheck?.(event, drl);\n if (match && responseCache) {\n cacheResponse(drl, url, response, responseCache);\n }\n return response;\n }\n console.log(`DWN endpoint error: ${response.status}`);\n lastError = new Response('DWeb Node request failed', {\n status: response.status,\n });\n } catch (error) {\n console.log(`DWN endpoint error: ${error}`);\n lastError = new Response('DWeb Node request failed', {\n status: 500,\n });\n }\n }\n return lastError!;\n}\n\n/** @internal Exported for testing. Caches a DRL response with metadata headers. */\nexport async function cacheResponse(drl: string, url: string, response: Response, cache: Cache): Promise<void> {\n try {\n const clonedResponse = response.clone();\n const headers = new Headers(clonedResponse.headers);\n headers.append('dwn-cache-time', Date.now().toString());\n headers.append('dwn-composed-url', url);\n const modifiedResponse = new Response(clonedResponse.body, { headers });\n await cache.put(drl, modifiedResponse);\n } catch (error) {\n console.log(`Failed to cache DRL response: ${error}`);\n }\n}\n\n/* Service Worker-based features */\n\nasync function installWorker(options: ActivatePolyfillsOptions = {}): Promise<void> {\n try {\n // Check to see if we are in a Service Worker already, if so, proceed\n // You can call the activatePolyfills() function in your own worker, or standalone as a root worker\n if (\n typeof ServiceWorkerGlobalScope !== 'undefined' &&\n self instanceof ServiceWorkerGlobalScope\n ) {\n const workerSelf = self as unknown as ServiceWorkerGlobalScope;\n workerSelf.skipWaiting();\n workerSelf.addEventListener('activate', (event: ExtendableEvent) => {\n // Claim clients to make the service worker take control immediately\n event.waitUntil(workerSelf.clients.claim());\n });\n workerSelf.addEventListener('fetch', (event: FetchEvent) => {\n const parsed = parseDrlUrl(event.request.url);\n if (parsed) {\n event.respondWith(handleEvent(event, parsed[0], parsed[1], options));\n }\n });\n }\n // If the code gets here, it is not a SW env, it is likely DOM, but check to be sure\n else if (globalThis?.navigator?.serviceWorker) {\n const registration = await navigator.serviceWorker.getRegistration('/');\n // You can only have one worker per path, so check to see if one is already registered\n if (!registration) {\n const installUrl: string | undefined =\n options.path ||\n (document?.currentScript as HTMLScriptElement | null)?.src ||\n import.meta.url;\n if (installUrl)\n {navigator.serviceWorker\n .register(installUrl, { type: 'module' })\n .catch((error: unknown) => {\n console.error(\n 'DWeb networking feature installation failed: ',\n error\n );\n });}\n }\n } else {\n throw new Error(\n 'DWeb networking features are not available for install in this environment'\n );\n }\n } catch (error) {\n console.error('Error in installing networking features:', error);\n }\n}\n\n/* DOM Environment Features */\n\nconst loaderStyles = `\n .drl-loading-overlay {\n position: fixed;\n inset: 0;\n display: flex;\n flex-wrap: wrap;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n color: #fff;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(15px);\n -webkit-backdrop-filter: blur(15px);\n z-index: 1000000;\n }\n\n .drl-loading-overlay > div {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .drl-loading-spinner {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .drl-loading-spinner div {\n position: relative;\n width: 2em;\n height: 2em;\n margin: 0.1em 0.25em 0 0;\n }\n .drl-loading-spinner div::after,\n .drl-loading-spinner div::before {\n content: ''; \n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 0.1em solid #FFF;\n position: absolute;\n left: 0;\n top: 0;\n opacity: 0;\n animation: drl-loading-spinner 2s linear infinite;\n }\n .drl-loading-spinner div::after {\n animation-delay: 1s;\n }\n\n .drl-loading-overlay span {\n --text-opacity: 2;\n display: flex;\n align-items: center;\n margin: 2em auto 0;\n padding: 0.2em 0.75em 0.25em;\n text-align: center;\n border-radius: 5em;\n background: rgba(255 255 255 / 8%);\n opacity: 0.8;\n transition: opacity 0.3s ease;\n cursor: pointer;\n }\n\n .drl-loading-overlay span:focus {\n opacity: 1;\n }\n\n .drl-loading-overlay span:hover {\n opacity: 1;\n }\n\n .drl-loading-overlay span::before {\n content: '\u2715 ';\n margin: 0 0.4em 0 0;\n color: red;\n font-size: 65%;\n font-weight: bold;\n }\n\n .drl-loading-overlay span::after {\n content: 'stop';\n display: block;\n font-size: 60%;\n line-height: 0;\n color: rgba(255 255 255 / 60%);\n }\n\n .drl-loading-overlay.new-tab-overlay span::after {\n content: 'close';\n }\n \n @keyframes drl-loading-spinner {\n 0% {\n transform: scale(0);\n opacity: 1;\n }\n 100% {\n transform: scale(1);\n opacity: 0;\n }\n }\n`;\nconst tabContent = `\n<!DOCTYPE html>\n<html lang='en'>\n<head>\n <meta charset='UTF-8'>\n <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n <title>Loading DRL...</title>\n <style>\n html, body {\n background-color: #151518;\n height: 100%;\n margin: 0;\n padding: 0;\n font-family: Arial, sans-serif;\n text-align: center;\n }\n ${loaderStyles}\n </style>\n</head>\n<body>\n <div class='drl-loading-overlay new-tab-overlay'>\n <div class='drl-loading-spinner'>\n <div></div>\n Loading DRL\n </div>\n <span onclick='window.close()' tabindex='0'></span>\n </div>\n</body>\n</html>\n`;\n\nlet elementsInjected = false;\nlet overlayElement: HTMLDivElement | null = null;\nlet styleElement: HTMLStyleElement | null = null;\n\nfunction injectElements(): void {\n if (elementsInjected) {return;}\n styleElement = document.createElement('style');\n styleElement.innerHTML = `\n ${loaderStyles}\n\n .drl-loading-overlay {\n opacity: 0;\n transition: opacity 0.3s ease;\n pointer-events: none;\n }\n\n :root[drl-link-loading] .drl-loading-overlay {\n opacity: 1;\n pointer-events: all;\n }\n `;\n document.head.append(styleElement);\n\n overlayElement = document.createElement('div');\n overlayElement.classList.add('drl-loading-overlay');\n overlayElement.innerHTML = `\n <div class='drl-loading-spinner'>\n <div></div>\n Loading DRL\n </div> \n <span tabindex='0'></span>\n `;\n overlayElement.lastElementChild!.addEventListener('click', cancelNavigation);\n document.body.prepend(overlayElement);\n elementsInjected = true;\n}\n\nfunction removeElements(): void {\n if (!elementsInjected) {return;}\n styleElement?.remove();\n styleElement = null;\n overlayElement?.remove();\n overlayElement = null;\n elementsInjected = false;\n}\n\nfunction cancelNavigation(): void {\n document.documentElement.removeAttribute('drl-link-loading');\n activeNavigation = null;\n}\n\nlet activeNavigation: string | null = null;\nlet linkFeaturesActive = false;\n\n// Stored references for listener cleanup in deactivatePolyfills()\nlet clickHandler: ((event: MouseEvent) => Promise<void>) | null = null;\nlet pointerdownHandler: ((event: PointerEvent) => Promise<void>) | null = null;\n\nfunction addLinkFeatures(): void {\n if (!linkFeaturesActive) {\n clickHandler = async (event: MouseEvent): Promise<void> => {\n const anchor = (event.target as Element)?.closest('a');\n if (anchor) {\n const href = anchor.href;\n const parsed = parseDrlUrl(href);\n if (parsed) {\n const did = parsed[0];\n const path = parsed[1];\n const openAsTab = anchor.target === '_blank';\n event.preventDefault();\n try {\n let tab: Window | null = null;\n if (openAsTab) {\n tab = window.open('', '_blank');\n if (tab) {tab.document.write(tabContent);}\n } else {\n activeNavigation = path;\n // this is to allow for cached DIDs to instantly load without any flash of loading UI\n setTimeout(\n () =>\n document.documentElement.setAttribute('drl-link-loading', ''),\n 50\n );\n }\n const endpoints = await getDwnEndpoints(did);\n if (!endpoints.length) {\n throw new Error('no valid DWN endpoints found');\n }\n const url = `${endpoints[0].replace(\n trailingSlashRegex,\n ''\n )}/${did}/${path}`;\n if (openAsTab) {\n if (tab && !tab.closed) {tab.location.href = url;}\n } else if (activeNavigation === path) {\n window.location.href = url;\n }\n } catch {\n if (activeNavigation === path) {\n cancelNavigation();\n }\n throw new Error(\n `DID endpoint resolution failed for the DRL: ${href}`\n );\n }\n }\n }\n };\n\n pointerdownHandler = async (event: PointerEvent): Promise<void> => {\n const target = event.composedPath()[0] as DrlMediaElement | undefined;\n if (\n (event.pointerType === 'mouse' && event.button === 2) ||\n (event.pointerType === 'touch' && event.isPrimary)\n ) {\n resetContextMenuTarget();\n if (target?.src && parseDrlUrl(target.src)) {\n contextMenuTarget = target;\n target.__src__ = target.src;\n const drl = target.src\n .replace(httpToHttpsRegex, 'https:')\n .replace(trailingSlashRegex, '');\n const responseCache = await openDrlCache();\n const response = await responseCache?.match(drl);\n if (response) {\n const url = response.headers.get('dwn-composed-url');\n if (url) {target.src = url;}\n }\n target.addEventListener('pointerup', resetContextMenuTarget, {\n once: true,\n });\n }\n } else if (target === contextMenuTarget) {\n resetContextMenuTarget();\n }\n };\n\n document.addEventListener('click', clickHandler);\n document.addEventListener('pointercancel', resetContextMenuTarget);\n document.addEventListener('pointerdown', pointerdownHandler);\n\n linkFeaturesActive = true;\n }\n}\n\nfunction removeLinkFeatures(): void {\n if (!linkFeaturesActive) {return;}\n if (clickHandler) {\n document.removeEventListener('click', clickHandler);\n clickHandler = null;\n }\n if (pointerdownHandler) {\n document.removeEventListener('pointerdown', pointerdownHandler);\n pointerdownHandler = null;\n }\n document.removeEventListener('pointercancel', resetContextMenuTarget);\n resetContextMenuTarget();\n cancelNavigation();\n linkFeaturesActive = false;\n}\n\nlet contextMenuTarget: DrlMediaElement | null = null;\nasync function resetContextMenuTarget(e?: Event): Promise<void> {\n if (e?.type === 'pointerup') {\n await new Promise<void>((r) => requestAnimationFrame(() => r()));\n }\n if (contextMenuTarget) {\n contextMenuTarget.src = contextMenuTarget.__src__!;\n delete contextMenuTarget.__src__;\n contextMenuTarget = null;\n }\n}\n\n/**\n * Activates various polyfills to enable Enbox features in Web environments.\n *\n * @param options - Configuration options to control the activation of polyfills.\n *\n * @example\n * // Activate all polyfills with default options, and cache every DRL for 1 minute\n * activatePolyfills({\n * onCacheCheck(event, route){\n * return {\n * ttl: 60_000\n * }\n * }\n * });\n *\n * @example\n * // Activate polyfills, but without Service Worker activation\n * activatePolyfills({ serviceWorker: false });\n *\n * @example\n * // Use custom DID resolvers\n * activatePolyfills({ didResolvers: [DidDht, DidWeb, DidJwk] });\n */\nexport function activatePolyfills(options: ActivatePolyfillsOptions = {}): void {\n if (options.didResolvers) {\n didResolver = new UniversalResolver({ didResolvers: options.didResolvers });\n }\n if (options.serviceWorker !== false) {\n installWorker(options);\n }\n if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {\n if (options.injectStyles !== false) {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', injectElements, {\n once: true,\n });\n } else {injectElements();}\n }\n if (options.links !== false) {addLinkFeatures();}\n }\n}\n\n/**\n * Removes all polyfill event listeners, injected DOM elements, and resets internal state.\n * Call this to fully clean up after {@link activatePolyfills}.\n *\n * Does **not** unregister an installed Service Worker \u2014 use\n * `navigator.serviceWorker.getRegistration('/').then(r => r?.unregister())` for that.\n */\nexport function deactivatePolyfills(): void {\n if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {\n removeLinkFeatures();\n removeElements();\n }\n}\n\n/**\n * Deletes the entire DRL response cache.\n * Useful for clearing stale cached DWN responses.\n *\n * @returns `true` if the cache existed and was deleted, `false` otherwise.\n * Returns `false` if the Cache API is unavailable.\n */\nexport async function clearDrlCache(): Promise<boolean> {\n if (typeof caches === 'undefined') {return false;}\n return caches.delete(DRL_CACHE_NAME);\n}\n", "/**\n * Parses a DRL URL (http(s)://dweb/{did}/{path}) without regex quantifiers.\n * Returns `[did, path]` or `null` if the URL does not match the DRL scheme.\n *\n * Extracted to a standalone module so it can be tested under Node.js (bun:test)\n * in addition to the browser-based vitest suite, ensuring SonarCloud's\n * merged coverage report includes these lines.\n */\nexport function parseDrlUrl(url: string): [string, string] | null {\n const idx = url.indexOf('://dweb/');\n if (idx === -1) { return null; }\n const prefix = url.slice(0, idx);\n if (prefix !== 'http' && prefix !== 'https') { return null; }\n const rest = url.slice(idx + 8); // '://dweb/'.length === 8\n if (rest.length === 0) { return null; }\n const slashIdx = rest.indexOf('/');\n if (slashIdx === -1) { return [rest, '']; }\n if (slashIdx === 0) { return null; } // DID segment must be non-empty\n return [rest.slice(0, slashIdx), rest.slice(slashIdx + 1)];\n}\n", "/**\n * Connect modal \u2014 the single surface that owns a whole connect session.\n *\n * One Shadow-DOM dialog whose stage morphs in place through the session:\n * QR / deep-link handoff (phone path) \u2192 pairing code \u2192 connected, with the\n * in-browser popup path and the wallet catalog folded in as in-place\n * alternates. The modal never chains into a second modal and stays mounted\n * until the session resolves (connected / denied / cancelled).\n *\n * Layout: three zones \u2014\n *\n * 1. **Header** \u2014 requesting app identity + close.\n * 2. **Stage** \u2014 a height-stable region where states crossfade: the\n * clickable QR (joined by a Continue deep-link button on phones; both\n * open the wallet in a new tab so this session stays alive underneath),\n * the pairing-code input, progress, success, and error states.\n * 3. **Footer** \u2014 the wallet identity row (\"Connecting with\" + the selected\n * wallet and the next catalog wallets as tiles), a More tile that expands\n * the remaining wallets as a matching grid (search + custom URL) in\n * place \u2014 a wallet is never shown twice \u2014 and the alternate-method link.\n *\n * Theming: the stylesheet is static and reads `--ec-*` design tokens.\n * Light/dark follows the visitor's system via `prefers-color-scheme` and\n * updates live; the embedding app can force an appearance or override\n * palette tokens through {@link ConnectModalOptions.theme}. Overrides are\n * applied as inline custom properties \u2014 never interpolated into the\n * stylesheet \u2014 so a hostile string can't escape its declaration. The QR\n * card alone is theme-invariant (dark modules on white scan most\n * reliably).\n *\n * The phone path drives the `@enbox/connect` relay transport via\n * {@link runRelayConnect}; the browser path drives the popup transport via\n * the kernel `ConnectClient`. Wallet `connectServerUrl`s are discovered\n * from each wallet's `/.well-known/enbox-connect` document unless\n * overridden.\n *\n * @module\n */\n\nimport type { PortableDid } from '@enbox/dids';\nimport type { WalletOption } from '../browser-connect-handler.js';\nimport type { ConnectPermissionRequest, ConnectRequestType, ConnectResult, WalletUriHandoff } from '@enbox/connect';\n\nimport { ConnectClient } from '@enbox/connect';\n\nimport { buildWalletIcon } from './wallet-icon.js';\nimport {\n collectBrowserClientMetadata,\n PopupClientTransport,\n PopupWindowClosedError,\n} from '../dweb-connect-client.js';\nimport { encodeQr, qrToSvg } from './qr.js';\nimport { fetchWalletWellKnown, probeWalletWellKnown } from './wallet-well-known.js';\nimport { RelayConnectCancelledError, runRelayConnect } from '../relay-connect-runner.js';\n\n/** How the user carries out the approval. */\nexport type ConnectMethod = 'phone' | 'browser';\n\n/** localStorage key remembering the last successful method + wallet. */\nconst LAST_CHOICE_STORAGE_KEY = 'enbox:connect:lastChoice';\n\n/**\n * Safety margin subtracted from the relay pointer TTL before re-minting.\n *\n * The pointer is single-use and its TTL starts at mint time, but the wallet\n * only dereferences it after the user scans \u2014 and, on a locked wallet, after\n * they finish the unlock ceremony. A scanned code must therefore carry\n * enough remaining life to absorb that whole window, so re-mint well before\n * the deadline rather than just ahead of it.\n */\nconst REMINT_SAFETY_MS = 120_000;\n\n/** Minimum delay before an automatic re-mint. */\nconst REMINT_MIN_MS = 10_000;\n\n/** Pairing code length (matches the wallet's generated PIN). */\nconst PIN_LENGTH = 4;\n\n/** Catalog size beyond which the wallet switcher shows its search bar. */\nconst WALLET_SEARCH_THRESHOLD = 4; // one full row of tiles\n\n/** Wallet tiles shown in the collapsed identity row (plus the More tile). */\nconst WALLET_ROW_SIZE = 3;\n\n/** Palette overrides for one appearance's design tokens. */\nexport interface ConnectModalPalette {\n /** Modal surface. */\n background?: string;\n\n /** Inset surfaces: tiles, inputs, hover fills. */\n surface?: string;\n\n /** Primary text. */\n text?: string;\n\n /** Secondary text. */\n textMuted?: string;\n\n /** Hairline borders and dividers. */\n border?: string;\n\n /** Brand accent: buttons, links, focus rings, selection. */\n accent?: string;\n\n /** Text/icon color on accent surfaces. */\n accentContrast?: string;\n\n /** Error text and invalid-input borders. */\n danger?: string;\n\n /** Success surfaces (the connected check). */\n success?: string;\n}\n\n/** Optional color scheme provided by the embedding app. */\nexport interface ConnectModalTheme {\n /**\n * Follow the visitor's system appearance (`'auto'`, live-updating) or\n * force one.\n * @default 'auto'\n */\n appearance?: 'auto' | 'light' | 'dark';\n\n /** Brand accent applied in both appearances (per-scheme palettes win). */\n accent?: string;\n\n /** Text/icon color on accent surfaces, in both appearances. */\n accentContrast?: string;\n\n /** Token overrides applied while the light appearance is active. */\n light?: ConnectModalPalette;\n\n /** Token overrides applied while the dark appearance is active. */\n dark?: ConnectModalPalette;\n}\n\n/** Design-token custom property behind each palette key. */\nconst PALETTE_TOKENS: Record<keyof ConnectModalPalette, string> = {\n background : '--ec-bg',\n surface : '--ec-surface',\n text : '--ec-text',\n textMuted : '--ec-muted',\n border : '--ec-border',\n accent : '--ec-accent',\n accentContrast : '--ec-accent-contrast',\n danger : '--ec-danger',\n success : '--ec-success',\n};\n\n/** Options for {@link runConnectModal}. */\nexport interface ConnectModalOptions {\n /** Wallet catalog shown in the wallet switcher. */\n wallets?: WalletOption[];\n\n /**\n * Explicit wallet URL: hides the catalog switcher and uses this wallet\n * for both methods.\n */\n walletUrl?: string;\n\n /** User-facing mode. Absent means a normal connect. */\n mode?: ConnectRequestType;\n\n /** Existing delegate credentials reused by a refresh request. */\n delegatePortableDid?: PortableDid;\n\n /** Preferred method on open; overrides the remembered choice. */\n preferredMethod?: ConnectMethod;\n\n /**\n * Remember the successful method + wallet in localStorage and pre-shape\n * the next session accordingly.\n * @default true\n */\n rememberChoice?: boolean;\n\n /** Display name of the requesting application. */\n appName?: string;\n\n /** Icon URL of the requesting application. */\n appIcon?: string;\n\n /**\n * Relay base URL override for the phone path. When omitted, each wallet's\n * `connectServerUrl` is discovered from its `/.well-known/enbox-connect`\n * document.\n */\n connectServerUrl?: string;\n\n /**\n * Path appended to the wallet origin to form the QR / deep-link target.\n * @default '/connect/app'\n */\n relayWalletPath?: string;\n\n /** Timeout in milliseconds for either method's handshake. */\n timeout?: number;\n\n /**\n * Color scheme. By default the modal follows the visitor's system\n * light/dark appearance; apps can force an appearance and/or override\n * palette tokens per scheme to match their brand.\n */\n theme?: ConnectModalTheme;\n\n /** DWN protocols and permission scopes being requested. */\n permissionRequests: ConnectPermissionRequest[];\n\n /** Internal dependency seams (tests). */\n deps?: Partial<ConnectModalDeps>;\n}\n\n/** Injectable collaborators, defaulted to the real implementations. */\nexport interface ConnectModalDeps {\n /** Runs one relay handshake (phone path). */\n runRelay: typeof runRelayConnect;\n\n /** Runs one popup handshake (browser path); must open the popup synchronously. */\n runPopup: (options: {\n walletUrl: string;\n permissionRequests: ConnectPermissionRequest[];\n appName: string;\n appIcon?: string;\n timeoutMs?: number;\n delegatePortableDid?: PortableDid;\n requestType?: ConnectRequestType;\n }) => Promise<ConnectResult | undefined>;\n\n /** Resolves a wallet origin to its relay `connectServerUrl` (or undefined). */\n discoverConnectServerUrl: (walletOrigin: string) => Promise<string | undefined>;\n\n /** Validates a pasted custom wallet URL. */\n validateWalletUrl: (origin: string) => Promise<boolean>;\n\n /** Whether to present the deep-link (same-device) variant of the phone path. */\n isMobile: () => boolean;\n\n /** Persistence for the remembered choice. */\n storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | undefined;\n}\n\n/**\n * Resolves a wallet origin to its relay `connectServerUrl` via the wallet's\n * `/.well-known/enbox-connect` document ({@link fetchWalletWellKnown} \u2014 the\n * same machinery the wallet selector uses for custom-URL validation).\n */\nexport async function discoverWalletConnectServerUrl(walletOrigin: string): Promise<string | undefined> {\n return (await fetchWalletWellKnown(walletOrigin))?.connectServerUrl;\n}\n\n/** Runs one popup handshake without collapsing early-close into a denial. */\nasync function runPopupConnect(options: {\n walletUrl: string;\n permissionRequests: ConnectPermissionRequest[];\n appName: string;\n appIcon?: string;\n timeoutMs?: number;\n delegatePortableDid?: PortableDid;\n requestType?: ConnectRequestType;\n}): Promise<ConnectResult | undefined> {\n // The transport constructor calls `window.open` synchronously \u2014 callers\n // must invoke this inside the user-gesture call stack.\n const transport = new PopupClientTransport({\n walletUrl : options.walletUrl,\n timeoutMs : options.timeoutMs,\n });\n const client = new ConnectClient({ transport });\n\n return await client.connect({\n appName : options.appName,\n appIcon : options.appIcon,\n clientMetadata : collectBrowserClientMetadata(),\n permissionRequests : options.permissionRequests,\n delegatePortableDid : options.delegatePortableDid,\n requestType : options.requestType,\n });\n}\n\nfunction defaultIsMobile(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n const coarse = window.matchMedia?.('(pointer: coarse)').matches ?? false;\n return coarse && Math.min(window.innerWidth, window.innerHeight) < 900;\n}\n\nfunction defaultDeps(): ConnectModalDeps {\n return {\n runRelay : runRelayConnect,\n runPopup : runPopupConnect,\n discoverConnectServerUrl : discoverWalletConnectServerUrl,\n validateWalletUrl : probeWalletWellKnown,\n isMobile : defaultIsMobile,\n storage : typeof localStorage === 'undefined' ? undefined : localStorage,\n };\n}\n\n/** Remembered method + wallet from a previous successful session. */\ninterface LastChoice {\n method: ConnectMethod;\n walletUrl: string;\n}\n\nfunction readLastChoice(storage: ConnectModalDeps['storage']): LastChoice | undefined {\n try {\n const raw = storage?.getItem(LAST_CHOICE_STORAGE_KEY);\n if (raw == null) {\n return undefined;\n }\n const parsed = JSON.parse(raw) as Partial<LastChoice>;\n if ((parsed.method === 'phone' || parsed.method === 'browser') && isValidRememberedWalletUrl(parsed.walletUrl)) {\n return { method: parsed.method, walletUrl: parsed.walletUrl };\n }\n } catch { /* unreadable storage \u2014 behave as first visit */ }\n return undefined;\n}\n\nfunction writeLastChoice(storage: ConnectModalDeps['storage'], choice: LastChoice): void {\n try {\n storage?.setItem(LAST_CHOICE_STORAGE_KEY, JSON.stringify(choice));\n } catch { /* best effort */ }\n}\n\n/** One cancellable relay session. */\ninterface RelaySession {\n cancelled: Promise<never>;\n cancel: () => void;\n active: boolean;\n}\n\nfunction createRelaySession(): RelaySession {\n let cancel!: () => void;\n const session: Partial<RelaySession> = { active: true };\n const cancelled = new Promise<never>((_, reject) => {\n cancel = (): void => {\n if (session.active === true) {\n session.active = false;\n reject(new RelayConnectCancelledError());\n }\n };\n });\n // Mark handled so an unconsumed cancellation never surfaces as unhandled.\n cancelled.catch((): undefined => undefined);\n session.cancelled = cancelled;\n session.cancel = cancel;\n return session as RelaySession;\n}\n\n/**\n * Opens the connect modal and resolves when the session ends.\n *\n * @returns The delegated credentials; `undefined` when the user denied the\n * request in the wallet (or dismissed after a denial).\n * @throws When the user cancels the modal, or the session fails and the\n * user dismisses the error.\n */\nexport function runConnectModal(options: ConnectModalOptions): Promise<ConnectResult | undefined> {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n throw new Error('[@enbox/browser] The connect modal is only available in browser environments.');\n }\n if (options.mode === 'refresh' && options.delegatePortableDid === undefined) {\n throw new Error('Connect: refresh requests require an existing `delegatePortableDid`.');\n }\n\n const deps: ConnectModalDeps = { ...defaultDeps(), ...options.deps };\n const wallets = dedupeWalletsByUrl(options.wallets ?? []);\n const rememberChoice = options.rememberChoice ?? true;\n const appName = options.appName ?? window.location.host;\n const relayWalletPath = options.relayWalletPath ?? '/connect/app';\n const isMobile = deps.isMobile();\n const refreshing = options.mode === 'refresh';\n\n const lastChoice = rememberChoice ? readLastChoice(deps.storage) : undefined;\n\n // Wallet resolution order: explicit option \u2192 remembered \u2192 catalog head.\n const rememberedWalletUrl = lastChoice !== undefined\n && (refreshing || walletInCatalog(wallets, lastChoice.walletUrl))\n ? lastChoice.walletUrl\n : undefined;\n const lockedWallet = options.walletUrl !== undefined || (refreshing && rememberedWalletUrl !== undefined);\n let walletUrl = options.walletUrl\n ?? rememberedWalletUrl\n ?? wallets[0]?.url;\n\n // Method resolution order: explicit option \u2192 remembered \u2192 phone.\n let method: ConnectMethod = options.preferredMethod ?? lastChoice?.method ?? 'phone';\n\n return new Promise<ConnectResult | undefined>((resolve, reject) => {\n // \u2500\u2500 Host + shadow root \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const host = document.createElement('div');\n host.id = 'enbox-connect-modal';\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = MODAL_STYLES;\n shadow.appendChild(style);\n\n const overlay = document.createElement('div');\n overlay.className = 'overlay';\n const modal = document.createElement('div');\n modal.className = 'modal';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n const title = refreshing ? `Reconnect to ${appName}` : `Connect to ${appName}`;\n modal.setAttribute('aria-label', title);\n\n // \u2500\u2500 Theme \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // System light/dark is pure CSS (`prefers-color-scheme`), so it tracks\n // the visitor live. A forced appearance pins the token block instead.\n const theme = options.theme ?? {};\n const appearance = theme.appearance ?? 'auto';\n if (appearance !== 'auto') {\n modal.setAttribute('data-appearance', appearance);\n }\n\n // Dapp palette overrides land as inline custom properties: setProperty\n // parses each value as a lone declaration, so a hostile string cannot\n // escape into the stylesheet.\n const systemDark = window.matchMedia?.('(prefers-color-scheme: dark)');\n const hasPaletteOverrides = theme.accent !== undefined || theme.accentContrast !== undefined\n || theme.light !== undefined || theme.dark !== undefined;\n const applyPaletteTokens = (): void => {\n const scheme = appearance === 'auto'\n ? (systemDark?.matches === true ? 'dark' : 'light')\n : appearance;\n const palette: ConnectModalPalette = {\n accent : theme.accent,\n accentContrast : theme.accentContrast,\n ...theme[scheme],\n };\n for (const key of Object.keys(PALETTE_TOKENS) as Array<keyof ConnectModalPalette>) {\n const value = palette[key];\n if (typeof value === 'string' && value.trim() !== '') {\n modal.style.setProperty(PALETTE_TOKENS[key], value);\n } else {\n modal.style.removeProperty(PALETTE_TOKENS[key]);\n }\n }\n };\n const onSchemeChange = (): void => applyPaletteTokens();\n if (hasPaletteOverrides) {\n applyPaletteTokens();\n if (appearance === 'auto') {\n systemDark?.addEventListener?.('change', onSchemeChange);\n }\n }\n\n // \u2500\u2500 Session state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let settled = false;\n let relaySession: RelaySession | undefined;\n let remintTimer: ReturnType<typeof setTimeout> | undefined;\n let remintAt: number | undefined;\n let popupBusy = false;\n let pinResolve: ((pin: string) => void) | undefined;\n const discoveryCache = new Map<string, Promise<string | undefined>>();\n\n // Collapsed identity row: the selected wallet plus the next catalog\n // wallets, never repeating one. Slots stay stable across in-row\n // switches (only the highlight moves); the row recomposes only when a\n // wallet from outside it \u2014 grid pick or custom URL \u2014 becomes selected,\n // which puts that wallet in the first slot.\n let rowWallets: WalletOption[] = [];\n\n /** The catalog entry for `url`, or a synthesized option for custom URLs. */\n const walletByUrl = (url: string): WalletOption =>\n wallets.find((wallet) => wallet.url === url) ?? { name: hostnameOf(url) ?? url, url };\n\n const composeWalletRow = (): void => {\n if (walletUrl === undefined) {\n rowWallets = wallets.slice(0, WALLET_ROW_SIZE);\n return;\n }\n if (rowWallets.some((wallet) => wallet.url === walletUrl)) {\n return;\n }\n const selected = walletByUrl(walletUrl);\n rowWallets = [selected, ...wallets.filter((wallet) => wallet.url !== selected.url)].slice(0, WALLET_ROW_SIZE);\n };\n\n const selectWallet = (url: string): void => {\n walletUrl = url;\n renderFooter();\n void startMethod();\n };\n\n const cleanup = (): void => {\n relaySession?.cancel();\n clearRemint();\n document.removeEventListener('keydown', onKeydown);\n document.removeEventListener('visibilitychange', onVisibilityReturn);\n systemDark?.removeEventListener?.('change', onSchemeChange);\n try { document.body.removeChild(host); } catch { /* best effort */ }\n };\n\n const settle = (settler: () => void): void => {\n if (settled) { return; }\n settled = true;\n cleanup();\n settler();\n };\n\n const succeed = (result: ConnectResult): void => {\n if (rememberChoice) {\n writeLastChoice(deps.storage, { method, walletUrl: walletUrl ?? '' });\n }\n renderConnected();\n const finish = (): void => settle(() => resolve(result));\n setTimeout(finish, 1_200);\n };\n\n const cancelModal = (): void => settle(() => reject(new Error('[@enbox/browser] Connect cancelled.')));\n\n // \u2500\u2500 Zones \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n modal.appendChild(buildHeader(title, options.appIcon, cancelModal));\n\n const stage = document.createElement('div');\n stage.className = 'stage';\n stage.setAttribute('aria-live', 'polite');\n modal.appendChild(stage);\n\n const footer = document.createElement('div');\n footer.className = 'footer';\n modal.appendChild(footer);\n\n // \u2500\u2500 Stage renderers (all render in place; nothing navigates) \u2500\u2500\n const setStage = (...nodes: (HTMLElement | SVGElement)[]): void => {\n stage.replaceChildren(...nodes);\n stage.classList.remove('fade-in');\n void stage.offsetWidth; // restart the transition\n stage.classList.add('fade-in');\n };\n\n const renderBusy = (message: string): void => {\n setStage(el('div', 'spinner'), el('p', 'stage-caption', message));\n };\n\n /**\n * Schedules the \"finish in the wallet\" morph after a handoff link is\n * followed. Deferred one tick so the anchor's default new-tab navigation\n * completes before the anchor is replaced, and guarded so a session that\n * moved on meanwhile (re-mint, wallet response, settle) is never\n * overwritten.\n */\n const morphToAway = (walletName: string): void => {\n const session = relaySession;\n setTimeout((): void => {\n if (settled || session !== relaySession || session?.active !== true || pinResolve !== undefined) {\n return;\n }\n renderAway(walletName);\n }, 0);\n };\n\n /**\n * Builds one same-device handoff anchor for the wallet URI. The wallet\n * opens in a new tab so this modal \u2014 and the relay session under it \u2014\n * stays alive, with the pairing-code entry waiting when the user\n * switches back. `noopener` keeps the wallet tab from reaching back into\n * this one.\n */\n const buildHandoffLink = (handoff: WalletUriHandoff, walletName: string, className: string): HTMLAnchorElement => {\n const link = document.createElement('a');\n link.className = className;\n link.href = handoff.walletUri;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.addEventListener('click', () => { morphToAway(walletName); });\n return link;\n };\n\n const renderQr = (handoff: WalletUriHandoff): void => {\n const wallet = walletUrl !== undefined ? walletByUrl(walletUrl) : undefined;\n const walletName = wallet?.name ?? 'your wallet';\n\n // The QR card is itself a handoff link on every device: opening it on\n // this device runs the exact handshake the camera path runs on another\n // one, and scanning it keeps working either way.\n const qrLink = buildHandoffLink(handoff, walletName, 'qr-box qr-link');\n qrLink.setAttribute('aria-label', `Open ${walletName} on this device`);\n // Fixed colors on the white card: dark-on-light QRs scan reliably in\n // both appearances (inverted codes trip up some camera apps).\n qrLink.replaceChildren(qrToSvg(encodeQr(handoff.walletUri), {\n dark : '#14141f',\n light : 'transparent',\n quietZone : 2,\n }));\n\n // The selected wallet's mark sits at the QR centre \u2014 the \"this is the\n // wallet you're connecting to\" cue. The 44px plate over the ~180px\n // symbol occludes ~5% of modules, well inside ECC level M's 15%\n // recovery budget (the compact variant scales the plate down to\n // match).\n if (wallet !== undefined) {\n const logo = el('div', 'qr-logo');\n logo.appendChild(buildWalletIcon(wallet));\n qrLink.appendChild(logo);\n }\n\n if (isMobile) {\n const link = buildHandoffLink(handoff, walletName, 'deep-link');\n if (wallet !== undefined) {\n link.appendChild(buildWalletIcon(wallet));\n }\n link.appendChild(el('span', 'deep-link-label', `Continue in ${walletName}`));\n\n qrLink.classList.add('compact');\n setStage(\n link,\n el('p', 'stage-subline', `${walletName} opens in a new tab \u2014 approve there, then come back for your code.`),\n el('div', 'stage-divider', 'or scan with another phone'),\n qrLink,\n );\n return;\n }\n\n setStage(\n qrLink,\n el('p', 'stage-caption', 'Scan with your phone\u2019s camera'),\n el('p', 'stage-subline', `${walletName} stays on your phone \u2014 or click the code to open it here.`),\n );\n };\n\n /**\n * Shown once a handoff link is followed on this device: the approval is\n * happening in the wallet tab, this one waits for the code. \"Start over\"\n * mints a fresh pointer \u2014 the right recovery, because the pointer the\n * wallet tab carried away is single-use.\n */\n const renderAway = (walletName: string): void => {\n setStage(\n el('div', 'spinner'),\n el('p', 'stage-caption', `Finish in ${walletName}`),\n el('p', 'stage-subline', isMobile\n ? `Approve the connection in the ${walletName} tab, then come back here for your code.`\n : 'Approve the connection in the tab that just opened, then come back here for your code.'),\n stageLinkButton('Start over', () => { void startPhone(); }),\n );\n };\n\n const renderClaimed = (): void => {\n const walletName = walletUrl !== undefined ? walletByUrl(walletUrl).name : 'your wallet';\n const pulse = document.createElement('div');\n pulse.className = 'claimed-pulse';\n setStage(\n pulse,\n el('p', 'stage-caption', `Request received \u2014 approve in ${walletName}`),\n el('p', 'stage-subline', 'Once you approve, you\u2019ll get a code to enter here.'),\n );\n };\n\n const renderPin = (attempt: number, previousError?: Error): Promise<string> => {\n return new Promise<string>((resolvePin) => {\n pinResolve = resolvePin;\n const walletName = walletUrl !== undefined ? walletByUrl(walletUrl).name : 'your wallet';\n\n const boxes = document.createElement('div');\n boxes.className = 'pin-row';\n if (previousError !== undefined) {\n boxes.classList.add('shake');\n }\n\n const inputs: HTMLInputElement[] = [];\n for (let i = 0; i < PIN_LENGTH; i++) {\n const input = document.createElement('input');\n input.className = 'pin-input';\n input.type = 'text';\n input.inputMode = 'numeric';\n input.maxLength = 1;\n input.setAttribute('aria-label', `Code digit ${i + 1}`);\n inputs.push(input);\n boxes.appendChild(input);\n }\n\n const submitIfComplete = (): void => {\n const code = inputs.map((i) => i.value).join('');\n if (code.length === PIN_LENGTH && pinResolve !== undefined) {\n const resolveOnce = pinResolve;\n pinResolve = undefined;\n renderBusy('Checking the code\u2026');\n resolveOnce(code);\n }\n };\n\n inputs.forEach((input, index) => {\n input.addEventListener('input', () => {\n input.value = input.value.replace(/\\D/g, '').slice(0, 1);\n if (input.value !== '' && index + 1 < inputs.length) {\n inputs[index + 1].focus();\n }\n submitIfComplete();\n });\n input.addEventListener('keydown', (event) => {\n if (event.key === 'Backspace' && input.value === '' && index > 0) {\n inputs[index - 1].focus();\n }\n });\n input.addEventListener('paste', (event) => {\n const digits = (event.clipboardData?.getData('text') ?? '').replace(/\\D/g, '').slice(0, PIN_LENGTH);\n if (digits.length === 0) { return; }\n event.preventDefault();\n digits.split('').forEach((digit, digitIndex) => {\n if (inputs[digitIndex] !== undefined) {\n inputs[digitIndex].value = digit;\n }\n });\n inputs[Math.min(digits.length, PIN_LENGTH) - 1]?.focus();\n submitIfComplete();\n });\n });\n\n setStage(\n el('p', 'stage-caption', `Enter the code shown in ${walletName}`),\n boxes,\n ...(previousError !== undefined\n ? [el('p', 'stage-error', `That code doesn\u2019t match \u2014 check ${walletName}.`)]\n : [el('p', 'stage-subline', attempt === 1 ? 'This confirms you\u2019re the one approving.' : '')]),\n );\n\n inputs[0].focus();\n });\n };\n\n const renderConnected = (): void => {\n const check = el('div', 'check');\n check.textContent = '\u2713';\n setStage(check, el('p', 'stage-caption', 'You\u2019re connected.'));\n };\n\n const renderDenied = (): void => {\n setStage(\n el('p', 'stage-caption', 'No problem \u2014 nothing was shared.'),\n stageButton('Start over', () => { void startMethod(); }),\n stageLinkButton('Close', () => settle(() => resolve(undefined))),\n );\n };\n\n const renderError = (message: string, error?: Error): void => {\n setStage(\n el('p', 'stage-caption', message),\n stageButton('Start over', () => { void startMethod(); }),\n stageLinkButton('Close', () => settle(() => reject(error ?? new Error(`[@enbox/browser] ${message}`)))),\n );\n };\n\n const renderPhoneUnavailable = (): void => {\n setStage(\n el('p', 'stage-caption', 'This wallet can\u2019t connect by phone here.'),\n el('p', 'stage-subline', 'You can continue in this browser instead.'),\n stageButton('Use this browser', () => { startPopup(); }),\n );\n };\n\n // The popup surface is a small window on desktop but a new tab on\n // phones \u2014 the copy names whichever the visitor will actually see.\n const popupSurface = isMobile ? 'tab' : 'window';\n\n const renderPopupPrompt = (): void => {\n setStage(\n el('p', 'stage-caption', 'Connect with a wallet in this browser'),\n el('p', 'stage-subline', isMobile\n ? 'Your wallet opens in a new tab to approve this connection \u2014 no code needed.'\n : 'Your wallet opens in a small window to approve this connection.'),\n stageButton(isMobile ? 'Open wallet' : 'Open wallet window', () => { startPopup(); }),\n );\n };\n\n const renderPopupWaiting = (): void => {\n setStage(\n el('div', 'spinner'),\n el('p', 'stage-caption', `Finish in the wallet ${popupSurface}`),\n el('p', 'stage-subline', 'We\u2019ll wrap up here as soon as you\u2019re done.'),\n );\n };\n\n const renderPopupInterrupted = (blocked: boolean): void => {\n setStage(\n el('p', 'stage-caption', blocked\n ? `Your browser blocked the wallet ${popupSurface}.`\n : `The wallet ${popupSurface} was closed.`),\n stageButton(blocked ? 'Open it now' : `Reopen ${popupSurface}`, () => { startPopup(); }),\n stageLinkButton(isMobile ? 'Use a code instead' : 'Use your phone instead', () => { void switchMethod('phone'); }),\n );\n };\n\n const renderPopupFailure = (error: unknown): void => {\n if (settled) { return; }\n\n const failure = error instanceof Error ? error : new Error(String(error));\n const popupBlocked = /popup blocked/i.test(failure.message);\n if (error instanceof PopupWindowClosedError || popupBlocked) {\n renderPopupInterrupted(popupBlocked);\n return;\n }\n\n renderError(\n /timed out/i.test(failure.message)\n ? 'That took too long, so we stopped for safety.'\n : 'Something went wrong while connecting.',\n failure,\n );\n };\n\n // \u2500\u2500 Method drivers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const resolveConnectServerUrl = async (origin: string): Promise<string | undefined> => {\n if (options.connectServerUrl !== undefined) {\n return options.connectServerUrl;\n }\n let cached = discoveryCache.get(origin);\n if (cached === undefined) {\n cached = deps.discoverConnectServerUrl(origin);\n discoveryCache.set(origin, cached);\n }\n return cached;\n };\n\n const clearRemint = (): void => {\n clearTimeout(remintTimer);\n remintAt = undefined;\n };\n\n const remintNow = (): void => {\n // Never re-mint once the wallet has responded (pairing in progress).\n if (!settled && pinResolve === undefined && method === 'phone') {\n void startPhone();\n }\n };\n\n const scheduleRemint = (expiresInSeconds: number): void => {\n clearRemint();\n const delay = Math.max(REMINT_MIN_MS, expiresInSeconds * 1_000 - REMINT_SAFETY_MS);\n // The deadline is kept alongside the timer: background tabs (mobile\n // especially) throttle or freeze timers, so the visibility handler\n // re-checks it when the user returns.\n remintAt = Date.now() + delay;\n remintTimer = setTimeout(remintNow, delay);\n };\n\n const startPhone = async (): Promise<void> => {\n relaySession?.cancel();\n clearRemint();\n\n if (walletUrl === undefined) {\n renderError('No wallet is configured.');\n return;\n }\n\n method = 'phone';\n renderFooter();\n renderBusy('Getting things ready\u2026');\n\n const origin = new URL(walletUrl).origin;\n const connectServerUrl = await resolveConnectServerUrl(origin);\n if (connectServerUrl === undefined) {\n renderPhoneUnavailable();\n return;\n }\n\n const session = createRelaySession();\n relaySession = session;\n\n try {\n const result = await deps.runRelay({\n connectServerUrl,\n walletUri : new URL(relayWalletPath, origin).toString(),\n appName,\n appIcon : options.appIcon,\n clientMetadata : collectBrowserClientMetadata(),\n permissionRequests : options.permissionRequests,\n delegatePortableDid : options.delegatePortableDid,\n requestType : options.mode,\n timeoutMs : options.timeout,\n cancelled : session.cancelled,\n onWalletUriReady : (handoff): void => {\n if (session.active && !settled) {\n renderQr(handoff);\n scheduleRemint(handoff.expiresIn);\n }\n },\n onClaimed: (): void => {\n if (session.active && !settled) {\n // The wallet has the request \u2014 stop re-minting (a new pointer\n // would orphan the approval in progress) and show progress.\n clearRemint();\n renderClaimed();\n }\n },\n requestPin: (attempt, previousError): Promise<string> => {\n clearRemint();\n return renderPin(attempt, previousError);\n },\n });\n\n if (!session.active || settled) { return; }\n\n if (result === undefined) {\n renderDenied();\n } else {\n succeed(result);\n }\n } catch (error) {\n if (!session.active || settled || error instanceof RelayConnectCancelledError) {\n return;\n }\n const failure = error instanceof Error ? error : new Error(String(error));\n renderError(\n /timed out/i.test(failure.message)\n ? 'That took too long, so we stopped for safety.'\n : 'Something went wrong while connecting.',\n failure,\n );\n }\n };\n\n const startPopup = (): void => {\n // Synchronous popup open inside the click's call stack.\n relaySession?.cancel();\n clearRemint();\n\n if (walletUrl === undefined) {\n renderError('No wallet is configured.');\n return;\n }\n if (popupBusy) { return; }\n\n method = 'browser';\n renderFooter();\n\n popupBusy = true;\n renderPopupWaiting();\n\n try {\n deps.runPopup({\n walletUrl,\n permissionRequests : options.permissionRequests,\n appName,\n appIcon : options.appIcon,\n timeoutMs : options.timeout,\n delegatePortableDid : options.delegatePortableDid,\n requestType : options.mode,\n })\n .then((result) => {\n if (settled) { return; }\n if (result === undefined) {\n renderDenied();\n } else {\n succeed(result);\n }\n })\n .catch(renderPopupFailure)\n .finally(() => { popupBusy = false; });\n } catch (error) {\n popupBusy = false;\n renderPopupFailure(error);\n }\n };\n\n const startMethod = async (): Promise<void> => {\n if (method === 'browser') {\n // window.open must stay inside a user gesture \u2014 prompt for the click.\n relaySession?.cancel();\n clearRemint();\n renderFooter();\n renderPopupPrompt();\n } else {\n await startPhone();\n }\n };\n\n const switchMethod = async (next: ConnectMethod): Promise<void> => {\n method = next;\n await startMethod();\n };\n\n // \u2500\u2500 Footer: identity row (+ catalog panel), method link below \u2500\u2500\n const renderFooter = (): void => {\n footer.replaceChildren();\n\n if (!lockedWallet) {\n composeWalletRow();\n const switcher = buildWalletSwitcher();\n if (switcher.label !== undefined) {\n footer.appendChild(switcher.label);\n }\n footer.appendChild(switcher.row);\n footer.appendChild(switcher.panel);\n }\n\n const row = document.createElement('div');\n row.className = 'footer-row';\n\n if (method === 'phone') {\n const alt = document.createElement('button');\n alt.className = 'footer-link method-link';\n // On a phone both methods open the wallet on this device \u2014 what the\n // popup channel actually buys the visitor is skipping the code.\n alt.textContent = isMobile ? 'Or connect without a code \u2192' : 'No phone? Use this browser \u2192';\n // startPopup runs synchronously in this click handler.\n alt.addEventListener('click', () => { startPopup(); });\n row.appendChild(alt);\n } else {\n const alt = document.createElement('button');\n alt.className = 'footer-link method-link';\n alt.textContent = isMobile ? 'Use a code instead \u2192' : 'Use your phone instead \u2192';\n alt.addEventListener('click', () => { void switchMethod('phone'); });\n row.appendChild(alt);\n }\n\n if (row.childElementCount > 0) {\n footer.appendChild(row);\n }\n };\n\n const buildWalletSwitcher = (): { label?: HTMLElement; row: HTMLDivElement; panel: HTMLDivElement } => {\n // Identity row: selected wallet + the next catalog wallets, then the\n // More tile expanding the full catalog in place.\n const row = document.createElement('div');\n row.className = 'wallet-row';\n row.setAttribute('role', 'radiogroup');\n row.setAttribute('aria-label', 'Wallet');\n\n for (const wallet of rowWallets) {\n const tile = document.createElement('button');\n tile.className = 'row-tile';\n tile.title = wallet.description ?? wallet.name;\n tile.setAttribute('role', 'radio');\n const isSelected = wallet.url === walletUrl;\n tile.setAttribute('aria-checked', isSelected ? 'true' : 'false');\n if (isSelected) {\n tile.classList.add('selected');\n }\n tile.appendChild(buildWalletIcon(wallet));\n tile.appendChild(el('span', 'row-tile-name', wallet.name));\n tile.addEventListener('click', () => {\n if (wallet.url !== walletUrl) {\n selectWallet(wallet.url);\n }\n });\n row.appendChild(tile);\n }\n\n const panel = document.createElement('div');\n panel.className = 'wallet-panel';\n panel.hidden = true;\n\n // The panel grid holds only the wallets NOT already visible in the\n // row, so expanding never shows the same wallet twice.\n const gridWallets = wallets.filter((wallet) => !rowWallets.some((shown) => shown.url === wallet.url));\n\n const more = document.createElement('button');\n more.className = 'row-tile more-tile';\n more.title = 'All wallets';\n more.setAttribute('aria-expanded', 'false');\n more.appendChild(el('span', 'more-count', gridWallets.length > 0 ? `+${gridWallets.length}` : '\u22EF'));\n more.appendChild(el('span', 'row-tile-name', 'More'));\n more.addEventListener('click', () => {\n panel.hidden = !panel.hidden;\n more.setAttribute('aria-expanded', panel.hidden ? 'false' : 'true');\n if (!panel.hidden) {\n updateScrollHint();\n }\n });\n row.appendChild(more);\n\n const label = rowWallets.length > 0 ? el('div', 'wallet-row-label', 'Connecting with') : undefined;\n\n // Search filter \u2014 appears once the grid outgrows one row of tiles.\n const tiles: Array<{ wallet: (typeof wallets)[number]; el: HTMLButtonElement }> = [];\n const empty = document.createElement('div');\n empty.className = 'wallet-empty';\n empty.textContent = 'No other wallets match your search.';\n empty.hidden = true;\n\n if (gridWallets.length > WALLET_SEARCH_THRESHOLD) {\n const search = document.createElement('input');\n search.type = 'search';\n search.className = 'wallet-search';\n search.placeholder = 'Search wallets\u2026';\n search.setAttribute('aria-label', 'Search wallets');\n search.addEventListener('input', () => {\n const query = search.value.trim().toLowerCase();\n let visible = 0;\n for (const { wallet, el: tile } of tiles) {\n const match = query === ''\n || wallet.name.toLowerCase().includes(query)\n || wallet.url.toLowerCase().includes(query);\n tile.hidden = !match;\n if (match) { visible += 1; }\n }\n empty.hidden = visible > 0;\n updateScrollHint();\n });\n panel.appendChild(search);\n }\n\n // Tiles matching the identity row, four per row; past three rows the\n // grid scrolls in place, with a bottom fade hinting at more below.\n const scrollWrap = document.createElement('div');\n scrollWrap.className = 'wallet-scroll-wrap';\n scrollWrap.hidden = gridWallets.length === 0;\n const scroll = document.createElement('div');\n scroll.className = 'wallet-scroll';\n const grid = document.createElement('div');\n grid.className = 'wallet-grid';\n\n const updateScrollHint = (): void => {\n const overflowing = scroll.scrollHeight - scroll.clientHeight > 1;\n const atEnd = scroll.scrollTop + scroll.clientHeight >= scroll.scrollHeight - 1;\n scrollWrap.classList.toggle('scroll-hint', overflowing && !atEnd);\n };\n scroll.addEventListener('scroll', updateScrollHint);\n\n for (const wallet of gridWallets) {\n const tile = document.createElement('button');\n tile.className = 'wallet-tile';\n tile.title = wallet.description ?? wallet.name;\n tile.appendChild(buildWalletIcon(wallet));\n const tileName = document.createElement('span');\n tileName.className = 'wallet-tile-name';\n tileName.textContent = wallet.name;\n tile.appendChild(tileName);\n tile.addEventListener('click', () => {\n selectWallet(wallet.url);\n });\n tiles.push({ wallet, el: tile });\n grid.appendChild(tile);\n }\n scroll.appendChild(grid);\n scroll.appendChild(empty);\n scrollWrap.appendChild(scroll);\n panel.appendChild(scrollWrap);\n\n // Custom wallet URL (the power-user path, demoted to the disclosure).\n const custom = document.createElement('div');\n custom.className = 'wallet-custom';\n const input = document.createElement('input');\n input.className = 'url-input';\n input.type = 'url';\n input.placeholder = 'https://your-wallet.example';\n const go = document.createElement('button');\n go.className = 'url-go';\n go.textContent = 'Use';\n const urlError = document.createElement('div');\n urlError.className = 'url-error';\n urlError.hidden = true;\n\n // When validation fails we let the user override, since the connect\n // handshake is the ultimate gate \u2014 a valid wallet behind strict CORS\n // should not be permanently blocked.\n let allowUnverified = false;\n\n const submitCustom = async (): Promise<void> => {\n const value = input.value.trim();\n if (value === '') { return; }\n let origin: string;\n try {\n origin = new URL(value.includes('://') ? value : `https://${value}`).origin;\n } catch {\n input.classList.add('invalid');\n return;\n }\n if (allowUnverified) {\n selectWallet(origin);\n return;\n }\n go.disabled = true;\n go.textContent = 'Checking\u2026';\n urlError.hidden = true;\n const valid = await deps.validateWalletUrl(origin);\n go.disabled = false;\n if (valid) {\n go.textContent = 'Use';\n selectWallet(origin);\n return;\n }\n allowUnverified = true;\n go.textContent = 'Use anyway';\n input.classList.add('invalid');\n urlError.textContent = `Couldn't verify a wallet at ${origin}.`;\n urlError.hidden = false;\n };\n\n input.addEventListener('input', () => {\n allowUnverified = false;\n go.textContent = 'Use';\n input.classList.remove('invalid');\n urlError.hidden = true;\n });\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') { void submitCustom(); }\n });\n go.addEventListener('click', () => { void submitCustom(); });\n custom.appendChild(input);\n custom.appendChild(go);\n panel.appendChild(custom);\n panel.appendChild(urlError);\n\n return { label, row, panel };\n };\n\n // \u2500\u2500 Global interactions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n overlay.addEventListener('click', (event) => {\n if (event.target === overlay) {\n cancelModal();\n }\n });\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n cancelModal();\n return;\n }\n if (event.key === 'Tab') {\n trapFocus(shadow, event);\n }\n };\n document.addEventListener('keydown', onKeydown);\n\n // The visitor typically comes back from the wallet tab mid-session.\n const onVisibilityReturn = (): void => {\n if (document.visibilityState !== 'visible' || settled) {\n return;\n }\n\n // Background tabs throttle (or freeze) timers, so a re-mint that came\n // due while the user was away fires now instead of never.\n if (remintAt !== undefined && Date.now() >= remintAt) {\n remintNow();\n return;\n }\n\n // Returning with the code in hand: put the caret in the first empty\n // pairing-code box so they can type it straight away.\n if (pinResolve !== undefined) {\n const inputs = Array.from(shadow.querySelectorAll<HTMLInputElement>('.pin-input'));\n inputs.find((input) => input.value === '')?.focus();\n }\n };\n document.addEventListener('visibilitychange', onVisibilityReturn);\n\n overlay.appendChild(modal);\n shadow.appendChild(overlay);\n document.body.appendChild(host);\n\n renderFooter();\n void startMethod();\n });\n}\n\n// \u2500\u2500\u2500 Small DOM helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction walletInCatalog(wallets: WalletOption[], url: string): boolean {\n return wallets.some((wallet) => wallet.url === url);\n}\n\nfunction isValidRememberedWalletUrl(value: unknown): value is string {\n if (typeof value !== 'string' || value.trim() === '') {\n return false;\n }\n\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/** Drops catalog entries that repeat an earlier wallet's URL. */\nfunction dedupeWalletsByUrl(wallets: WalletOption[]): WalletOption[] {\n return wallets.filter((wallet, index) => wallets.findIndex((candidate) => candidate.url === wallet.url) === index);\n}\n\n/** Compact display form of a wallet URL for the switcher toggle. */\nfunction hostnameOf(url: string | undefined): string | undefined {\n if (url === undefined) {\n return undefined;\n }\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n\nfunction el(tag: string, className: string, text?: string): HTMLElement {\n const node = document.createElement(tag);\n node.className = className;\n if (text !== undefined) {\n node.textContent = text;\n }\n return node;\n}\n\nfunction stageButton(label: string, onClick: () => void): HTMLButtonElement {\n const button = document.createElement('button');\n button.className = 'stage-btn';\n button.textContent = label;\n button.addEventListener('click', onClick);\n return button;\n}\n\nfunction stageLinkButton(label: string, onClick: () => void): HTMLButtonElement {\n const button = document.createElement('button');\n button.className = 'footer-link';\n button.textContent = label;\n button.addEventListener('click', onClick);\n return button;\n}\n\nfunction buildHeader(titleText: string, appIcon: string | undefined, onCancel: () => void): HTMLDivElement {\n const header = document.createElement('div');\n header.className = 'header';\n\n const identity = document.createElement('div');\n identity.className = 'header-identity';\n\n if (appIcon !== undefined) {\n const icon = document.createElement('img');\n icon.className = 'header-icon';\n icon.src = appIcon;\n icon.alt = '';\n icon.width = 24;\n icon.height = 24;\n icon.addEventListener('error', () => icon.remove());\n identity.appendChild(icon);\n }\n\n const title = document.createElement('h2');\n title.textContent = titleText;\n identity.appendChild(title);\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'close-btn';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.textContent = '\\u00d7';\n closeBtn.addEventListener('click', onCancel);\n\n header.appendChild(identity);\n header.appendChild(closeBtn);\n return header;\n}\n\nfunction trapFocus(shadow: ShadowRoot, event: KeyboardEvent): void {\n const focusables = Array.from(\n shadow.querySelectorAll<HTMLElement>('button, input, a[href], [tabindex]:not([tabindex=\"-1\"])'),\n ).filter((node) => !node.hasAttribute('disabled') && node.offsetParent !== null);\n\n if (focusables.length === 0) {\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = shadow.activeElement as HTMLElement | null;\n\n if (event.shiftKey && (active === first || active === null)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n}\n\n// \u2500\u2500\u2500 Styles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// One static sheet; every color reads a `--ec-*` token. Light values sit on\n// `.modal`, dark values apply under `prefers-color-scheme` (so the system\n// appearance tracks live) and under a forced `data-appearance`. Dapp\n// palette overrides land as inline custom properties, which outrank all of\n// these \u2014 nothing user-provided is ever concatenated into this string.\n\n/** Light-appearance design tokens. */\nconst LIGHT_TOKENS = `\n --ec-bg: #ffffff;\n --ec-surface: #f5f6f8;\n --ec-text: #17171f;\n --ec-muted: #63636e;\n --ec-border: #e3e4e9;\n --ec-accent: #0a62d0;\n --ec-accent-contrast: #ffffff;\n --ec-danger: #c0392b;\n --ec-success: #1e9e5a;`;\n\n/** Dark-appearance design tokens. */\nconst DARK_TOKENS = `\n --ec-bg: #181822;\n --ec-surface: #23232f;\n --ec-text: #e9e9f0;\n --ec-muted: #9a9aa6;\n --ec-border: #33333f;\n --ec-accent: #58a6ff;\n --ec-accent-contrast: #0b1526;\n --ec-danger: #ff7a7a;\n --ec-success: #43d17c;`;\n\nconst MODAL_STYLES = `\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n /* Keep the hidden attribute authoritative: author display values (e.g.\n the panel's flex) would otherwise override the UA's [hidden] rule and\n leave \"collapsed\" sections permanently expanded. */\n [hidden] { display: none !important; }\n\n .overlay {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n background: rgba(0, 0, 0, 0.5);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n animation: fadeIn 0.15s ease-out;\n }\n\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }\n @keyframes stageIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes shake {\n 0%, 100% { transform: translateX(0); }\n 20%, 60% { transform: translateX(-6px); }\n 40%, 80% { transform: translateX(6px); }\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes claimedPulse {\n 0%, 100% { transform: scale(0.85); opacity: 0.7; }\n 50% { transform: scale(1); opacity: 1; }\n }\n\n .modal {${LIGHT_TOKENS}\n --ec-accent-soft: color-mix(in srgb, var(--ec-accent) 14%, transparent);\n background: var(--ec-bg);\n color: var(--ec-text);\n border-radius: 16px;\n width: 400px;\n max-width: 100%;\n max-height: calc(100vh - 32px);\n overflow-y: auto;\n padding: 16px 20px 12px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);\n animation: slideUp 0.2s ease-out;\n display: flex;\n flex-direction: column;\n }\n @media (prefers-color-scheme: dark) {\n .modal {${DARK_TOKENS}\n }\n }\n .modal[data-appearance='light'] {${LIGHT_TOKENS}\n }\n .modal[data-appearance='dark'] {${DARK_TOKENS}\n }\n\n button, input { font-family: inherit; }\n button:focus-visible, a:focus-visible {\n outline: 2px solid var(--ec-accent);\n outline-offset: 2px;\n }\n\n .header { display: flex; justify-content: space-between; align-items: center; gap: 8px; }\n .header-identity { display: flex; align-items: center; gap: 10px; min-width: 0; }\n .header-icon { border-radius: 6px; flex-shrink: 0; }\n h2 { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n .close-btn {\n background: none; border: none; font-size: 24px; cursor: pointer;\n color: var(--ec-muted); padding: 4px 8px; border-radius: 8px; line-height: 1;\n flex-shrink: 0;\n }\n .close-btn:hover { color: var(--ec-text); background: var(--ec-surface); }\n\n .stage {\n min-height: 240px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n text-align: center;\n padding: 12px 0 10px;\n }\n .stage.fade-in > * { animation: stageIn 0.15s ease-out; }\n\n .qr-box {\n position: relative;\n width: 200px;\n height: 200px;\n padding: 10px;\n border-radius: 12px;\n background: #ffffff;\n border: 1px solid #e3e4e9;\n }\n .qr-box svg { width: 100%; height: 100%; display: block; }\n\n /* Selected wallet's mark on the QR centre. Like the card, the plate is\n theme-invariant white so the logo sits on a scannable ground. */\n .qr-logo {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 44px;\n height: 44px;\n border-radius: 10px;\n background: #ffffff;\n border: 1px solid #e3e4e9;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .qr-logo .wallet-icon { width: 30px; height: 30px; }\n .qr-logo .wallet-badge { border-radius: 8px; font-size: 15px; }\n\n /* The QR card doubles as the same-device handoff link. */\n a.qr-box { display: block; cursor: pointer; }\n .qr-box.qr-link:hover {\n border-color: var(--ec-accent);\n box-shadow: 0 0 0 3px var(--ec-accent-soft);\n }\n .qr-box.compact { width: 160px; height: 160px; }\n .qr-box.compact .qr-logo { width: 36px; height: 36px; }\n .qr-box.compact .qr-logo .wallet-icon { width: 24px; height: 24px; }\n\n .stage-divider {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n color: var(--ec-muted);\n font-size: 12px;\n }\n .stage-divider::before, .stage-divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--ec-border);\n }\n\n .claimed-pulse {\n width: 64px; height: 64px; border-radius: 50%;\n background: var(--ec-accent-soft); position: relative;\n }\n .claimed-pulse::after {\n content: ''; position: absolute; inset: 18px; border-radius: 50%;\n background: var(--ec-accent);\n animation: claimedPulse 1.6s ease-in-out infinite;\n }\n\n .stage-caption { font-size: 15px; font-weight: 600; }\n .stage-subline { font-size: 13px; color: var(--ec-muted); max-width: 300px; line-height: 1.45; }\n .stage-error { font-size: 13px; color: var(--ec-danger); }\n\n .deep-link {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n width: 100%;\n padding: 13px 16px;\n border-radius: 12px;\n background: var(--ec-accent);\n color: var(--ec-accent-contrast);\n font-weight: 600;\n font-size: 15px;\n text-decoration: none;\n }\n .deep-link .wallet-icon { width: 24px; height: 24px; }\n .deep-link .wallet-badge {\n border-radius: 6px;\n font-size: 12px;\n background: var(--ec-accent-contrast);\n }\n .deep-link .wallet-img { border-radius: 6px; }\n\n .pin-row { display: flex; gap: 10px; }\n .pin-row.shake { animation: shake 0.4s ease-in-out; }\n .pin-input {\n width: 46px; height: 54px;\n text-align: center;\n font-size: 24px; font-weight: 600;\n color: var(--ec-text);\n background: var(--ec-surface);\n border: 1px solid var(--ec-border);\n border-radius: 10px;\n outline: none;\n }\n .pin-input:focus { border-color: var(--ec-accent); }\n\n .check {\n width: 56px; height: 56px;\n display: flex; align-items: center; justify-content: center;\n border-radius: 50%;\n background: var(--ec-success);\n color: #ffffff;\n font-size: 28px;\n }\n\n .spinner {\n width: 32px; height: 32px;\n border-radius: 50%;\n border: 3px solid var(--ec-border);\n border-top-color: var(--ec-accent);\n animation: spin 0.8s linear infinite;\n }\n\n .stage-btn {\n padding: 10px 20px;\n border: none;\n border-radius: 10px;\n background: var(--ec-accent);\n color: var(--ec-accent-contrast);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n }\n .stage-btn:hover { filter: brightness(1.08); }\n\n .footer {\n border-top: 1px solid var(--ec-border);\n padding-top: 8px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .footer-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 2px 8px;\n }\n .footer-row > * { min-width: 0; }\n .footer-row > :only-child { margin-inline: auto; }\n\n .footer-link {\n background: none;\n border: none;\n color: var(--ec-muted);\n font-size: 13px;\n cursor: pointer;\n padding: 5px 8px;\n border-radius: 8px;\n }\n .footer-link:hover { color: var(--ec-text); background: var(--ec-surface); }\n .method-link { color: var(--ec-accent); }\n\n .wallet-row-label { font-size: 12px; color: var(--ec-muted); padding: 2px 2px 0; }\n\n .wallet-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n }\n .row-tile, .wallet-tile {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 10px 6px;\n min-width: 0;\n background: var(--ec-surface);\n border: 1px solid var(--ec-border);\n border-radius: 12px;\n color: var(--ec-text);\n font-size: 11px;\n cursor: pointer;\n }\n .row-tile:hover, .wallet-tile:hover { border-color: var(--ec-accent); }\n .row-tile.selected {\n border-color: var(--ec-accent);\n background: var(--ec-accent-soft);\n box-shadow: inset 0 0 0 1px var(--ec-accent);\n }\n .row-tile.selected .row-tile-name { font-weight: 600; }\n .row-tile .wallet-icon, .wallet-tile .wallet-icon { width: 28px; height: 28px; }\n .row-tile-name, .wallet-tile-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n .more-tile { color: var(--ec-muted); }\n .more-tile:hover { color: var(--ec-text); }\n .more-tile[aria-expanded='true'] { border-color: var(--ec-accent); }\n .more-count {\n width: 28px;\n height: 28px;\n border-radius: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n background: var(--ec-accent-soft);\n color: var(--ec-accent);\n }\n\n .wallet-panel { width: 100%; padding: 4px 0 2px; display: flex; flex-direction: column; gap: 8px; }\n .wallet-search {\n width: 100%; padding: 8px 12px;\n border-radius: 10px; border: 1px solid var(--ec-border); background: transparent;\n color: inherit; font: inherit; font-size: 13px;\n }\n .wallet-search:focus { outline: none; border-color: var(--ec-accent); }\n\n /* Cap the grid at three rows of tiles; past that it scrolls in place,\n and the wrapper's bottom fade hints that more wallets are below. */\n .wallet-scroll-wrap { position: relative; }\n .wallet-scroll { max-height: 220px; overflow-y: auto; }\n .wallet-scroll-wrap.scroll-hint::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n height: 28px;\n background: linear-gradient(to bottom, transparent, var(--ec-bg));\n pointer-events: none;\n }\n .wallet-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n }\n\n .wallet-icon { position: relative; width: 28px; height: 28px; flex-shrink: 0; display: inline-flex; }\n .wallet-badge {\n width: 100%; height: 100%; border-radius: 8px; display: inline-flex;\n align-items: center; justify-content: center; font-size: 13px;\n font-weight: 600; background: var(--ec-accent-soft); color: var(--ec-accent);\n }\n .wallet-img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 8px; object-fit: cover; }\n\n .wallet-empty { padding: 10px 4px; font-size: 12px; color: var(--ec-muted); text-align: center; }\n\n .wallet-custom { display: flex; gap: 6px; }\n .url-input {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid var(--ec-border);\n border-radius: 10px;\n font-size: 13px;\n background: var(--ec-surface);\n color: var(--ec-text);\n outline: none;\n }\n .url-input:focus { border-color: var(--ec-accent); }\n .url-input.invalid { border-color: var(--ec-danger); }\n .url-go {\n padding: 8px 14px;\n border: none;\n border-radius: 10px;\n background: var(--ec-accent);\n color: var(--ec-accent-contrast);\n font-size: 13px;\n cursor: pointer;\n }\n .url-error { font-size: 12px; color: var(--ec-danger); }\n\n @media (prefers-reduced-motion: reduce) {\n .overlay, .modal, .stage.fade-in > *, .pin-row.shake { animation: none; }\n .claimed-pulse::after { animation: none; }\n }\n`;\n", "/**\n * Wallet icon builder shared by the connect modal's wallet switcher.\n *\n * Prefers the wallet's own favicon and degrades to a letter badge. We never\n * call a third-party favicon proxy: those 404 for many origins and leak the\n * wallet URL to the proxy.\n *\n * @module\n */\n\nimport type { WalletOption } from '../browser-connect-handler.js';\n\n/** Build a wallet icon element (own favicon with a letter-badge fallback). */\nexport function buildWalletIcon(wallet: WalletOption): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = 'wallet-icon';\n\n const badge = document.createElement('span');\n badge.className = 'wallet-badge';\n badge.textContent = wallet.name.charAt(0).toUpperCase();\n wrap.appendChild(badge);\n\n const sources = iconCandidates(wallet);\n if (sources.length === 0) {\n return wrap;\n }\n\n const img = document.createElement('img');\n img.className = 'wallet-img';\n img.alt = '';\n img.width = 28;\n img.height = 28;\n\n let index = 0;\n img.addEventListener('error', () => {\n index += 1;\n if (index < sources.length) {\n img.src = sources[index];\n } else {\n img.remove(); // fall back to the letter badge\n }\n });\n\n img.src = sources[index];\n wrap.appendChild(img);\n return wrap;\n}\n\n/** Ordered favicon URLs to try for a wallet, most specific first. */\nfunction iconCandidates(wallet: WalletOption): string[] {\n if (wallet.icon !== undefined) {\n return [wallet.icon];\n }\n\n let origin: string;\n try {\n origin = new URL(wallet.url).origin;\n } catch {\n return [];\n }\n\n return [`${origin}/favicon.svg`, `${origin}/favicon.ico`, `${origin}/favicon.png`];\n}\n", "/**\n * DWeb Connect client \u2014 the dapp side of the popup/postMessage connect flow.\n *\n * {@link PopupClientTransport} implements the `@enbox/connect` kernel's\n * `ConnectTransport` over a wallet popup:\n *\n * 1. The dapp opens `${walletUrl}/dweb-connect` as a popup window.\n * 2. The wallet emits a `loaded` beacon carrying a fresh ephemeral X25519\n * public key and its origin.\n * 3. The kernel seals the signed connect request to that key (ECDH-ES,\n * `apv` bound to the wallet origin) and the transport posts the\n * ciphertext to the popup.\n * 4. The wallet posts back the sealed response JWE (or the deny token),\n * which the kernel opens and value-checks.\n *\n * Only ciphertext crosses the postMessage channel. Every message is checked\n * against the wallet origin derived from the configured wallet URL (never\n * `'*'`), and against the popup window as `event.source`.\n *\n * @module\n */\n\nimport type { Jwk } from '@enbox/crypto';\nimport type {\n ConnectClientMetadata,\n ConnectPermissionRequest,\n ConnectRequestProfile,\n ConnectResult,\n ConnectTransport,\n} from '@enbox/connect';\n\nimport { assertX25519PublicJwk, CONNECT_DENIED_TOKEN, ConnectClient } from '@enbox/connect';\n\nimport {\n DWEB_CONNECT_ACK_MESSAGE_TYPE,\n DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n DWEB_CONNECT_PATH,\n DWEB_CONNECT_REQUEST_MESSAGE_TYPE,\n DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n getTrustedMessage,\n} from './dweb-connect-messages.js';\n\n/** Default budget for the whole popup handshake (beacon + user consent + response). */\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\n/** Interval at which the transport checks whether the user closed the popup. */\nconst CLOSED_POLL_INTERVAL_MS = 500;\n\n/**\n * Grace period after the popup is seen closed for an already-posted response\n * to finish delivery before the close is treated as a denial.\n */\nconst CLOSED_RESPONSE_GRACE_MS = 1_500;\n\n/** Window name given to the wallet popup. */\nconst POPUP_WINDOW_NAME = 'enbox-dweb-connect';\n\n/** Outer size of the wallet popup window. */\nconst POPUP_WIDTH = 500;\nconst POPUP_HEIGHT = 700;\n\n/**\n * Builds the wallet popup's window features, centring it over the opener\n * window \u2014 without `left`/`top` browsers park the popup wherever they like\n * (usually offset into a corner). Falls back to centring on the screen when\n * the opener's metrics are unavailable, and lets the browser clamp\n * off-screen coordinates. Mobile browsers ignore the features entirely and\n * open a tab.\n */\nfunction popupWindowFeatures(): string {\n const base = `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},menubar=no,toolbar=no,location=no,status=no`;\n\n // `screenX`/`outerWidth` describe the opener window; `screen.avail*`\n // describe its monitor \u2014 so the popup lands on the same display.\n const openerWidth = window.outerWidth > 0 ? window.outerWidth : (window.screen?.availWidth ?? 0);\n const openerHeight = window.outerHeight > 0 ? window.outerHeight : (window.screen?.availHeight ?? 0);\n if (openerWidth === 0 || openerHeight === 0) {\n return base;\n }\n\n const left = Math.max(0, Math.round((window.screenX ?? 0) + (openerWidth - POPUP_WIDTH) / 2));\n const top = Math.max(0, Math.round((window.screenY ?? 0) + (openerHeight - POPUP_HEIGHT) / 2));\n return `${base},left=${left},top=${top}`;\n}\n\n/** Guards against calling browser-only entry points outside a browser. */\nfunction assertBrowserEnvironment(): void {\n if (typeof window === 'undefined') {\n throw new Error('[@enbox/browser] DWeb Connect is only available in browser environments.');\n }\n}\n\n/**\n * Thrown when the user closes the wallet popup before the wallet finished\n * loading (i.e. before its `loaded` beacon arrived). Callers typically treat\n * this the same as a user denial.\n */\nexport class PopupWindowClosedError extends Error {\n constructor() {\n super('[@enbox/browser] Wallet popup was closed before the wallet finished loading.');\n this.name = 'PopupWindowClosedError';\n }\n}\n\n/** Options for constructing a {@link PopupClientTransport}. */\nexport type PopupClientTransportOptions = {\n /** Base URL of the wallet app (e.g. `https://enbox-wallet.pages.dev`). */\n walletUrl: string;\n\n /**\n * Total budget in milliseconds for the popup handshake. The popup is closed\n * and the handshake rejected when the wallet has not responded in time.\n * @default 300_000 (5 minutes)\n */\n timeoutMs?: number;\n};\n\n/**\n * Popup/postMessage {@link ConnectTransport} for browser dapps.\n *\n * Single-use: construct a new transport per handshake. The **constructor**\n * opens the wallet popup synchronously \u2014 so `window.open` runs inside the user\n * gesture, ahead of the kernel's awaited key generation, and survives strict\n * popup blockers; `requestProfile()` then awaits the wallet's `loaded` beacon;\n * `deliverRequest()` posts the sealed request ciphertext; `awaitResponse()`\n * resolves with the sealed response JWE, or the deny token when the user denies\n * or closes the popup after the handshake was established.\n *\n * Security properties:\n * - `targetOrigin` of every outbound `postMessage` is pinned to the origin\n * derived from `walletUrl` \u2014 never `'*'`.\n * - Inbound messages are dropped unless `event.origin` equals the pinned\n * wallet origin AND `event.source` is the popup window this transport opened.\n * - The beacon's `walletOrigin` field must equal the pinned origin, and its\n * `walletEpk` must be a public-only X25519 JWK; a malformed beacon from the\n * genuine popup fails the handshake closed.\n */\nexport class PopupClientTransport implements ConnectTransport {\n /** {@inheritDoc ConnectTransport.requiresPin} */\n public readonly requiresPin: boolean = false;\n\n private readonly _walletOrigin: string;\n private readonly _timeoutMs: number;\n\n private readonly _popup: Window;\n private _settled = false;\n private _walletEpkReceived = false;\n private _timeoutId?: ReturnType<typeof setTimeout>;\n private _closedPollId?: ReturnType<typeof setInterval>;\n private _messageListener?: (event: MessageEvent) => void;\n\n private readonly _walletEpkPromise: Promise<Jwk>;\n private _resolveWalletEpk?: (walletEpk: Jwk) => void;\n private _rejectWalletEpk?: (error: Error) => void;\n\n private readonly _responsePromise: Promise<string>;\n private _resolveResponse?: (payload: string) => void;\n private _rejectResponse?: (error: Error) => void;\n\n constructor(options: PopupClientTransportOptions) {\n assertBrowserEnvironment();\n\n this._walletOrigin = new URL(options.walletUrl).origin;\n this._timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n // Open the wallet popup SYNCHRONOUSLY, in the user-gesture call stack,\n // before the kernel's awaited `DidJwk.create()` / `X25519.generateKey()`\n // run. Strict popup blockers (Safari) reject a `window.open` issued once\n // the stack has yielded to a prior `await`, so opening it here \u2014 instead of\n // inside the awaited `requestProfile()` \u2014 is what keeps the flow usable.\n const popupUrl = new URL(DWEB_CONNECT_PATH, options.walletUrl).toString();\n const popup = window.open(popupUrl, POPUP_WINDOW_NAME, popupWindowFeatures());\n if (!popup) {\n throw new Error('[@enbox/browser] Popup blocked. Allow popups for this site to connect to a wallet.');\n }\n this._popup = popup;\n\n this._walletEpkPromise = new Promise<Jwk>((resolve, reject): void => {\n this._resolveWalletEpk = resolve;\n this._rejectWalletEpk = reject;\n });\n\n // Created up-front so a response (or deny) arriving before\n // `awaitResponse()` is called is never dropped. The no-op catch marks\n // early rejections (timeout, popup closed during load) as handled until\n // the kernel attaches its own handlers via `awaitResponse()`.\n this._responsePromise = new Promise<string>((resolve, reject): void => {\n this._resolveResponse = resolve;\n this._rejectResponse = reject;\n });\n this._responsePromise.catch((): undefined => undefined);\n\n // Listen synchronously, before the wallet page can emit its `loaded`\n // beacon, so the beacon is never missed while the kernel awaits key\n // generation ahead of `requestProfile()`.\n this._messageListener = (event: MessageEvent): void => { this.onMessage(event); };\n window.addEventListener('message', this._messageListener);\n\n this._timeoutId = setTimeout((): void => {\n this.fail(new Error('[@enbox/browser] DWeb Connect timed out waiting for wallet response.'));\n }, this._timeoutMs);\n\n this._closedPollId = setInterval((): void => { this.onClosedPoll(); }, CLOSED_POLL_INTERVAL_MS);\n }\n\n /**\n * Awaits the already-open popup's `loaded` beacon, then returns the popup\n * channel profile: ECDH-ES encryption to the beacon's ephemeral key with the\n * pinned wallet origin as the `apv` binding, a `post_message` reply\n * descriptor, and the client-supplied `state` correlator.\n *\n * The popup was opened synchronously at construction, so this method only\n * awaits the beacon \u2014 it never issues the blocker-sensitive `window.open`.\n *\n * @param state - The handshake correlator minted by the {@link ConnectClient}.\n * @throws If the user closes the popup before the beacon arrives\n * ({@link PopupWindowClosedError}), the beacon is malformed, or on\n * timeout.\n */\n public async requestProfile(state: string): Promise<ConnectRequestProfile> {\n const walletEpk = await this._walletEpkPromise;\n\n return {\n encryption : { mode: 'ecdh-es', walletEpk, walletOrigin: this._walletOrigin },\n reply : { mode: 'post_message' },\n state,\n };\n }\n\n /**\n * Posts the sealed request ciphertext to the wallet popup with the\n * `targetOrigin` pinned to the wallet origin.\n */\n public async deliverRequest(jwe: string): Promise<void> {\n this._popup.postMessage({ type: DWEB_CONNECT_REQUEST_MESSAGE_TYPE, jwe }, this._walletOrigin);\n }\n\n /**\n * Awaits the wallet's response ciphertext: the sealed response JWE, or the\n * deny token when the user denies in the wallet or closes the popup.\n * Rejects on timeout.\n */\n public async awaitResponse(): Promise<string> {\n return await this._responsePromise;\n }\n\n /**\n * {@inheritDoc ConnectTransport.confirmComplete}\n *\n * Posts the payload-less ack to the wallet popup (pinned `targetOrigin`)\n * so a wallet still holding its \"finishing up\" screen can flip to a\n * confirmed \"connected\" state before closing itself. A popup the user\n * already closed is skipped silently.\n */\n public async confirmComplete(): Promise<void> {\n if (this._popup.closed === true) { return; }\n this._popup.postMessage({ type: DWEB_CONNECT_ACK_MESSAGE_TYPE }, this._walletOrigin);\n }\n\n private onMessage(event: MessageEvent): void {\n const message = getTrustedMessage(event, this._walletOrigin, this._popup);\n if (message === undefined) { return; }\n\n if (message.type === DWEB_CONNECT_LOADED_MESSAGE_TYPE) {\n this.onLoadedBeacon(message);\n return;\n }\n\n if (message.type === DWEB_CONNECT_RESPONSE_MESSAGE_TYPE) {\n this.onResponseMessage(message);\n }\n }\n\n private onLoadedBeacon(message: Record<string, unknown>): void {\n if (this._settled || this._walletEpkReceived) { return; }\n\n // The beacon passed the origin and source checks, so a malformed payload\n // is a protocol violation by the genuine popup \u2014 fail closed. The X25519\n // public-JWK shape check is delegated to the connect kernel.\n let walletEpk: Jwk;\n try {\n assertX25519PublicJwk(message.walletEpk);\n walletEpk = message.walletEpk;\n } catch {\n this.fail(new Error('[@enbox/browser] Wallet loaded beacon did not carry a valid X25519 public key.'));\n return;\n }\n\n if (message.walletOrigin !== this._walletOrigin) {\n this.fail(new Error('[@enbox/browser] Wallet loaded beacon origin does not match the configured wallet origin.'));\n return;\n }\n\n this._walletEpkReceived = true;\n this._resolveWalletEpk?.(walletEpk);\n }\n\n private onResponseMessage(message: Record<string, unknown>): void {\n if (this._settled) { return; }\n\n if (typeof message.payload !== 'string') {\n this.fail(new Error('[@enbox/browser] Wallet response message did not carry a ciphertext payload.'));\n return;\n }\n\n this._settled = true;\n this.cleanup();\n // No-op on the normal path; unblocks `requestProfile()` if a response\n // somehow arrives before the beacon.\n this._rejectWalletEpk?.(new Error('[@enbox/browser] Wallet responded before the handshake was established.'));\n this._resolveResponse?.(message.payload);\n }\n\n private onClosedPoll(): void {\n if (this._settled || this._popup.closed !== true) { return; }\n\n if (!this._walletEpkReceived) {\n // Closed before the wallet ever loaded \u2014 the handshake cannot proceed.\n this.fail(new PopupWindowClosedError());\n return;\n }\n\n // Closed after the handshake was established. A wallet that posts its\n // response and immediately closes itself can lose the race between that\n // final message and this poll \u2014 especially when this page was\n // backgrounded (mobile tabs) and both signals arrive together on\n // resume \u2014 so give a queued response a grace window before treating the\n // close as a user denial.\n clearInterval(this._closedPollId);\n setTimeout((): void => {\n if (this._settled) { return; }\n this._settled = true;\n this.cleanup();\n this._resolveResponse?.(CONNECT_DENIED_TOKEN);\n }, CLOSED_RESPONSE_GRACE_MS);\n }\n\n private fail(error: Error): void {\n if (this._settled) { return; }\n this._settled = true;\n this.cleanup();\n try { this._popup.close(); } catch { /* best effort */ }\n this._rejectWalletEpk?.(error);\n this._rejectResponse?.(error);\n }\n\n private cleanup(): void {\n clearTimeout(this._timeoutId);\n clearInterval(this._closedPollId);\n if (this._messageListener !== undefined) {\n window.removeEventListener('message', this._messageListener);\n this._messageListener = undefined;\n }\n }\n}\n\n/** Options for a one-shot {@link connectViaPopup} flow. */\nexport type PopupConnectOptions = {\n /** Base URL of the wallet app (e.g. `https://enbox-wallet.pages.dev`). */\n walletUrl: string;\n\n /** DWN protocols and permission scopes to request from the wallet. */\n permissionRequests: ConnectPermissionRequest[];\n\n /**\n * Timeout in milliseconds for the popup handshake.\n * @default 300_000 (5 minutes)\n */\n timeout?: number;\n\n /**\n * Display name of the requesting application, shown in the wallet's\n * consent screen. Defaults to the dapp's host.\n */\n appName?: string;\n\n /**\n * Icon URL of the requesting application, shown alongside the app name in\n * the wallet's consent screen.\n */\n appIcon?: string;\n};\n\n/** Collects self-reported environment hints for the wallet's session display. */\nexport function collectBrowserClientMetadata(): ConnectClientMetadata {\n const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();\n const languages = Array.isArray(globalThis.navigator.languages)\n ? globalThis.navigator.languages.filter((language) => typeof language === 'string' && language.length > 0)\n : undefined;\n\n return {\n origin : globalThis.location.origin,\n userAgent : globalThis.navigator.userAgent,\n platform : globalThis.navigator.platform,\n language : globalThis.navigator.language,\n ...(languages && languages.length > 0 ? { languages } : {}),\n ...(resolvedOptions.timeZone ? { timezone: resolvedOptions.timeZone } : {}),\n };\n}\n\n/**\n * Runs one DWeb Connect popup handshake end-to-end: opens the wallet popup,\n * drives the `@enbox/connect` kernel client over a {@link PopupClientTransport},\n * and returns the delegated credentials.\n *\n * @returns The delegate credentials, or `undefined` when the user denied the\n * request or closed the popup.\n * @throws If the popup is blocked, the handshake times out, or the wallet\n * returns an invalid response.\n */\nexport async function connectViaPopup(options: PopupConnectOptions): Promise<ConnectResult | undefined> {\n const transport = new PopupClientTransport({\n walletUrl : options.walletUrl,\n timeoutMs : options.timeout,\n });\n const client = new ConnectClient({ transport });\n\n try {\n return await client.connect({\n appName : options.appName ?? globalThis.location.host,\n appIcon : options.appIcon,\n clientMetadata : collectBrowserClientMetadata(),\n permissionRequests : options.permissionRequests,\n });\n } catch (error) {\n if (error instanceof PopupWindowClosedError) {\n // The user closed the wallet before it loaded \u2014 same as a denial.\n return undefined;\n }\n throw error;\n }\n}\n", "/**\n * Wire shapes for the DWeb Connect popup/postMessage channel.\n *\n * The dapp and the wallet exchange exactly four message kinds over\n * `window.postMessage`:\n *\n * 1. `loaded` beacon (wallet \u2192 dapp): announces the wallet page is ready and\n * carries a fresh ephemeral X25519 public key plus the wallet's origin.\n * 2. `request` (dapp \u2192 wallet): the sealed connect request JWE \u2014 ciphertext\n * only, encrypted to the beacon key with ECDH-ES and the wallet origin\n * bound into the JWE `apv` header.\n * 3. `response` (wallet \u2192 dapp): the sealed connect response JWE, or the\n * literal deny token \u2014 again ciphertext only.\n * 4. `ack` (dapp \u2192 wallet): payload-less completion signal \u2014 the dapp opened\n * the response successfully, so the wallet can flip to a confirmed\n * \"connected\" state before closing itself. Optional and observational;\n * wallets unaware of it simply ignore the message.\n *\n * Plaintext never crosses the channel, and both sides pin `targetOrigin`\n * and verify `event.origin` / `event.source` on every message.\n *\n * @module\n */\n\nimport type { Jwk } from '@enbox/crypto';\n\n/** Path of the wallet's DWeb Connect page, opened as a popup by the dapp. */\nexport const DWEB_CONNECT_PATH = '/dweb-connect';\n\n/** Message type of the wallet's `loaded` beacon (wallet \u2192 dapp). */\nexport const DWEB_CONNECT_LOADED_MESSAGE_TYPE = 'enbox-connect-loaded';\n\n/** Message type carrying the sealed connect request JWE (dapp \u2192 wallet). */\nexport const DWEB_CONNECT_REQUEST_MESSAGE_TYPE = 'enbox-connect-request';\n\n/** Message type carrying the sealed connect response JWE or deny token (wallet \u2192 dapp). */\nexport const DWEB_CONNECT_RESPONSE_MESSAGE_TYPE = 'enbox-connect-response';\n\n/** Message type of the dapp's completion acknowledgement (dapp \u2192 wallet). */\nexport const DWEB_CONNECT_ACK_MESSAGE_TYPE = 'enbox-connect-ack';\n\n/**\n * The wallet's readiness beacon. Emitted to `window.opener` once the wallet's\n * DWeb Connect page has generated its per-session ephemeral X25519 key.\n */\nexport type DWebConnectLoadedMessage = {\n type: typeof DWEB_CONNECT_LOADED_MESSAGE_TYPE;\n\n /** Fresh ephemeral X25519 public JWK the dapp seals the request to. */\n walletEpk: Jwk;\n\n /** The wallet's own origin; must match the origin the dapp has pinned. */\n walletOrigin: string;\n};\n\n/** The dapp's sealed connect request, posted to the wallet popup. */\nexport type DWebConnectRequestMessage = {\n type: typeof DWEB_CONNECT_REQUEST_MESSAGE_TYPE;\n\n /** The sealed connect request as a Compact JWE string. */\n jwe: string;\n};\n\n/** The wallet's sealed connect response, posted back to the opener. */\nexport type DWebConnectResponseMessage = {\n type: typeof DWEB_CONNECT_RESPONSE_MESSAGE_TYPE;\n\n /** The sealed connect response JWE, or the literal `CONNECT_DENIED_TOKEN`. */\n payload: string;\n};\n\n/**\n * The dapp's completion acknowledgement: it opened the wallet's response\n * successfully. Carries no payload by design.\n */\nexport type DWebConnectAckMessage = {\n type: typeof DWEB_CONNECT_ACK_MESSAGE_TYPE;\n};\n\n/**\n * Applies the shared inbound-message trust filter for the popup channel:\n * pins the message to the expected `event.origin`, pins its `event.source` to\n * the expected window, and requires a non-null object payload.\n *\n * Returns the payload cast to a plain record when every check passes, or\n * `undefined` when the message must be dropped. Both the dapp-side and\n * wallet-side transports early-return on `undefined` before inspecting any\n * message field \u2014 this is the security-critical filter that keeps hostile\n * origins and stray windows off the channel.\n */\nexport function getTrustedMessage(\n event: MessageEvent,\n expectedOrigin: string,\n expectedSource: Window | undefined,\n): Record<string, unknown> | undefined {\n // Origin pinning: only messages from the expected origin count.\n if (event.origin !== expectedOrigin) { return undefined; }\n\n // Source pinning: the message must come from the expected window.\n if (event.source !== expectedSource) { return undefined; }\n\n const data: unknown = event.data;\n if (typeof data !== 'object' || data === null) { return undefined; }\n\n return data as Record<string, unknown>;\n}\n", "/**\n * Minimal QR code encoder \u2014 dependency-free, byte mode, ECC level M,\n * versions 1\u201310 with automatic version selection and standard mask\n * evaluation (ISO/IEC 18004 penalty rules N1\u2013N4).\n *\n * Scope is deliberately narrow: it exists to render wallet-connect URIs in\n * the connect modal without adding a third-party runtime dependency. The\n * encoding pipeline follows the standard exactly \u2014 segment \u2192 codewords \u2192\n * Reed-Solomon blocks \u2192 interleave \u2192 placement \u2192 mask \u2014 and the test suite\n * verifies full module-matrix equality against the `qrcode` npm package\n * (dev-only oracle) across versions and mask patterns.\n *\n * @module\n */\n\n/** An encoded QR symbol: `modules[y][x]` is `true` for dark modules. */\nexport interface QrCode {\n /** Symbol width/height in modules (17 + 4\u00D7version). */\n size: number;\n\n /** Dark/light module matrix, row-major. */\n modules: boolean[][];\n\n /** Symbol version (1\u201310). */\n version: number;\n\n /** Applied mask pattern (0\u20137). */\n mask: number;\n}\n\n/** Error-correction level M codewords per block, indexed by version (1\u201310). */\nconst ECC_PER_BLOCK = [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26];\n\n/** Error-correction level M block counts, indexed by version (1\u201310). */\nconst NUM_BLOCKS = [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5];\n\n/** Total codewords in the symbol, indexed by version (1\u201310). */\nconst TOTAL_CODEWORDS = [-1, 26, 44, 70, 100, 134, 172, 196, 242, 292, 346];\n\n/** Format-info error-correction bits for level M (`00` per the standard). */\nconst FORMAT_ECL_M = 0b00;\n\nconst MAX_VERSION = 10;\n\n/** Data codeword capacity for level M at `version`. */\nfunction dataCodewords(version: number): number {\n return TOTAL_CODEWORDS[version] - ECC_PER_BLOCK[version] * NUM_BLOCKS[version];\n}\n\n/**\n * Encodes UTF-8 text as a byte-mode QR symbol at ECC level M.\n *\n * @param text - The payload; encoded as UTF-8 bytes.\n * @param forcedMask - Optional mask override (0\u20137); defaults to the\n * penalty-minimising mask per the standard.\n * @returns The encoded symbol.\n * @throws If the payload does not fit in a version-10 level-M symbol.\n */\nexport function encodeQr(text: string, forcedMask?: number): QrCode {\n const data = new TextEncoder().encode(text);\n\n // \u2500\u2500 Version selection: smallest version that fits the segment. \u2500\u2500\n let version = 0;\n for (let candidate = 1; candidate <= MAX_VERSION; candidate++) {\n const capacityBits = dataCodewords(candidate) * 8;\n const headerBits = 4 + (candidate <= 9 ? 8 : 16);\n if (headerBits + data.length * 8 <= capacityBits) {\n version = candidate;\n break;\n }\n }\n if (version === 0) {\n throw new Error(`[@enbox/browser] QR payload too long (${data.length} bytes exceeds version ${MAX_VERSION}-M capacity).`);\n }\n\n // \u2500\u2500 Segment bits: mode 0100, char count, data, terminator, padding. \u2500\u2500\n const bits: number[] = [];\n const pushBits = (value: number, length: number): void => {\n for (let i = length - 1; i >= 0; i--) {\n bits.push((value >>> i) & 1);\n }\n };\n\n pushBits(0b0100, 4);\n pushBits(data.length, version <= 9 ? 8 : 16);\n for (const byte of data) {\n pushBits(byte, 8);\n }\n\n const capacityBits = dataCodewords(version) * 8;\n pushBits(0, Math.min(4, capacityBits - bits.length)); // terminator\n pushBits(0, (8 - (bits.length % 8)) % 8); // byte align\n\n const padBytes = [0xEC, 0x11];\n for (let i = 0; bits.length < capacityBits; i++) {\n pushBits(padBytes[i % 2], 8);\n }\n\n const codewords = new Uint8Array(capacityBits / 8);\n for (let i = 0; i < bits.length; i++) {\n codewords[i >> 3] |= bits[i] << (7 - (i & 7));\n }\n\n // \u2500\u2500 Reed-Solomon blocks + interleave. \u2500\u2500\n const allCodewords = buildInterleavedCodewords(codewords, version);\n\n // \u2500\u2500 Module placement. \u2500\u2500\n const size = 17 + 4 * version;\n const modules: boolean[][] = Array.from({ length: size }, () => new Array<boolean>(size).fill(false));\n const isFunction: boolean[][] = Array.from({ length: size }, () => new Array<boolean>(size).fill(false));\n\n drawFunctionPatterns(modules, isFunction, version);\n drawCodewords(modules, isFunction, allCodewords);\n\n // \u2500\u2500 Mask selection: apply each mask, score, keep the best. \u2500\u2500\n let mask = forcedMask ?? -1;\n if (mask === -1) {\n let bestPenalty = Infinity;\n for (let candidate = 0; candidate < 8; candidate++) {\n applyMask(modules, isFunction, candidate);\n drawFormatBits(modules, isFunction, candidate);\n const penalty = computePenalty(modules);\n if (penalty < bestPenalty) {\n bestPenalty = penalty;\n mask = candidate;\n }\n applyMask(modules, isFunction, candidate); // undo (XOR is involutive)\n }\n }\n\n applyMask(modules, isFunction, mask);\n drawFormatBits(modules, isFunction, mask);\n\n return { size, modules, version, mask };\n}\n\n/** Splits data codewords into level-M blocks, computes ECC, interleaves. */\nfunction buildInterleavedCodewords(data: Uint8Array, version: number): Uint8Array {\n const numBlocks = NUM_BLOCKS[version];\n const eccLen = ECC_PER_BLOCK[version];\n const totalCodewords = TOTAL_CODEWORDS[version];\n\n const numShortBlocks = numBlocks - (totalCodewords % numBlocks);\n const shortBlockLen = Math.floor(totalCodewords / numBlocks);\n\n const blocks: Uint8Array[] = [];\n const eccBlocks: Uint8Array[] = [];\n const rsDivisor = reedSolomonDivisor(eccLen);\n\n let offset = 0;\n for (let i = 0; i < numBlocks; i++) {\n const dataLen = shortBlockLen - eccLen + (i < numShortBlocks ? 0 : 1);\n const block = data.slice(offset, offset + dataLen);\n offset += dataLen;\n blocks.push(block);\n eccBlocks.push(reedSolomonRemainder(block, rsDivisor));\n }\n\n const result = new Uint8Array(totalCodewords);\n let index = 0;\n const maxDataLen = shortBlockLen - eccLen + 1;\n for (let i = 0; i < maxDataLen; i++) {\n for (let b = 0; b < numBlocks; b++) {\n if (i < blocks[b].length) {\n result[index++] = blocks[b][i];\n }\n }\n }\n for (let i = 0; i < eccLen; i++) {\n for (let b = 0; b < numBlocks; b++) {\n result[index++] = eccBlocks[b][i];\n }\n }\n\n return result;\n}\n\n// \u2500\u2500 GF(256) Reed-Solomon (polynomial 0x11D) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction gfMultiply(x: number, y: number): number {\n let z = 0;\n for (let i = 7; i >= 0; i--) {\n z = (z << 1) ^ ((z >>> 7) * 0x11D);\n z ^= ((y >>> i) & 1) * x;\n }\n return z & 0xFF;\n}\n\n/** Generator polynomial coefficients for `degree` ECC codewords. */\nfunction reedSolomonDivisor(degree: number): Uint8Array {\n const result = new Uint8Array(degree);\n result[degree - 1] = 1;\n\n let root = 1;\n for (let i = 0; i < degree; i++) {\n for (let j = 0; j < degree; j++) {\n result[j] = gfMultiply(result[j], root);\n if (j + 1 < degree) {\n result[j] ^= result[j + 1];\n }\n }\n root = gfMultiply(root, 0x02);\n }\n return result;\n}\n\nfunction reedSolomonRemainder(data: Uint8Array, divisor: Uint8Array): Uint8Array {\n const result = new Uint8Array(divisor.length);\n for (const byte of data) {\n const factor = byte ^ result[0];\n result.copyWithin(0, 1);\n result[result.length - 1] = 0;\n for (let i = 0; i < divisor.length; i++) {\n result[i] ^= gfMultiply(divisor[i], factor);\n }\n }\n return result;\n}\n\n// \u2500\u2500 Function patterns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Alignment pattern centre coordinates, indexed by version (1\u201310). */\nconst ALIGNMENT_POSITIONS: number[][] = [\n [], [],\n [6, 18], [6, 22], [6, 26], [6, 30], [6, 34],\n [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50],\n];\n\nfunction setFunctionModule(\n modules: boolean[][],\n isFunction: boolean[][],\n x: number,\n y: number,\n dark: boolean,\n): void {\n modules[y][x] = dark;\n isFunction[y][x] = true;\n}\n\nfunction drawFunctionPatterns(modules: boolean[][], isFunction: boolean[][], version: number): void {\n const size = modules.length;\n\n // Timing patterns.\n for (let i = 0; i < size; i++) {\n setFunctionModule(modules, isFunction, 6, i, i % 2 === 0);\n setFunctionModule(modules, isFunction, i, 6, i % 2 === 0);\n }\n\n // Finder patterns (with separators) at three corners.\n drawFinderPattern(modules, isFunction, 3, 3);\n drawFinderPattern(modules, isFunction, size - 4, 3);\n drawFinderPattern(modules, isFunction, 3, size - 4);\n\n // Alignment patterns: all pairs except the three finder corners.\n const positions = ALIGNMENT_POSITIONS[version];\n for (let i = 0; i < positions.length; i++) {\n for (let j = 0; j < positions.length; j++) {\n const skip =\n (i === 0 && j === 0) ||\n (i === 0 && j === positions.length - 1) ||\n (i === positions.length - 1 && j === 0);\n if (!skip) {\n drawAlignmentPattern(modules, isFunction, positions[i], positions[j]);\n }\n }\n }\n\n // Format-info reserved areas (drawn with mask later, but the modules must\n // be marked as function modules before codeword placement).\n drawFormatBits(modules, isFunction, 0);\n\n // Dark module.\n setFunctionModule(modules, isFunction, 8, size - 8, true);\n\n // Version information (versions \u2265 7).\n if (version >= 7) {\n drawVersionBits(modules, isFunction, version);\n }\n}\n\nfunction drawFinderPattern(modules: boolean[][], isFunction: boolean[][], cx: number, cy: number): void {\n const size = modules.length;\n for (let dy = -4; dy <= 4; dy++) {\n for (let dx = -4; dx <= 4; dx++) {\n const x = cx + dx;\n const y = cy + dy;\n if (x < 0 || x >= size || y < 0 || y >= size) {\n continue;\n }\n const distance = Math.max(Math.abs(dx), Math.abs(dy));\n setFunctionModule(modules, isFunction, x, y, distance !== 2 && distance !== 4);\n }\n }\n}\n\nfunction drawAlignmentPattern(modules: boolean[][], isFunction: boolean[][], cx: number, cy: number): void {\n for (let dy = -2; dy <= 2; dy++) {\n for (let dx = -2; dx <= 2; dx++) {\n setFunctionModule(modules, isFunction, cx + dx, cy + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);\n }\n }\n}\n\n/** 15-bit format info: 5 data bits BCH(15,5)-expanded, XORed with 0x5412. */\nfunction drawFormatBits(modules: boolean[][], isFunction: boolean[][], mask: number): void {\n const size = modules.length;\n\n const data = (FORMAT_ECL_M << 3) | mask;\n let rem = data;\n for (let i = 0; i < 10; i++) {\n rem = (rem << 1) ^ ((rem >>> 9) * 0x537);\n }\n const bits = ((data << 10) | rem) ^ 0x5412;\n\n // Around the top-left finder.\n for (let i = 0; i <= 5; i++) {\n setFunctionModule(modules, isFunction, 8, i, ((bits >>> i) & 1) !== 0);\n }\n setFunctionModule(modules, isFunction, 8, 7, ((bits >>> 6) & 1) !== 0);\n setFunctionModule(modules, isFunction, 8, 8, ((bits >>> 7) & 1) !== 0);\n setFunctionModule(modules, isFunction, 7, 8, ((bits >>> 8) & 1) !== 0);\n for (let i = 9; i < 15; i++) {\n setFunctionModule(modules, isFunction, 14 - i, 8, ((bits >>> i) & 1) !== 0);\n }\n\n // Second copy: below the top-right finder and beside the bottom-left one.\n for (let i = 0; i < 8; i++) {\n setFunctionModule(modules, isFunction, size - 1 - i, 8, ((bits >>> i) & 1) !== 0);\n }\n for (let i = 8; i < 15; i++) {\n setFunctionModule(modules, isFunction, 8, size - 15 + i, ((bits >>> i) & 1) !== 0);\n }\n}\n\n/** 18-bit version info (versions \u2265 7): 6 data bits + BCH(18,6) remainder. */\nfunction drawVersionBits(modules: boolean[][], isFunction: boolean[][], version: number): void {\n const size = modules.length;\n\n let rem = version;\n for (let i = 0; i < 12; i++) {\n rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);\n }\n const bits = (version << 12) | rem;\n\n for (let i = 0; i < 18; i++) {\n const bit = ((bits >>> i) & 1) !== 0;\n const a = size - 11 + (i % 3);\n const b = Math.floor(i / 3);\n setFunctionModule(modules, isFunction, a, b, bit);\n setFunctionModule(modules, isFunction, b, a, bit);\n }\n}\n\n/** Zig-zag codeword placement over non-function modules. */\nfunction drawCodewords(modules: boolean[][], isFunction: boolean[][], codewords: Uint8Array): void {\n const size = modules.length;\n let bitIndex = 0;\n\n for (let right = size - 1; right >= 1; right -= 2) {\n if (right === 6) {\n right = 5;\n }\n for (let vertical = 0; vertical < size; vertical++) {\n for (let j = 0; j < 2; j++) {\n const x = right - j;\n const upward = ((right + 1) & 2) === 0;\n const y = upward ? size - 1 - vertical : vertical;\n if (!isFunction[y][x] && bitIndex < codewords.length * 8) {\n modules[y][x] = ((codewords[bitIndex >> 3] >>> (7 - (bitIndex & 7))) & 1) !== 0;\n bitIndex++;\n }\n }\n }\n }\n}\n\n/** XORs the mask pattern over non-function modules (involutive). */\nfunction applyMask(modules: boolean[][], isFunction: boolean[][], mask: number): void {\n const size = modules.length;\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n if (isFunction[y][x]) {\n continue;\n }\n let invert: boolean;\n switch (mask) {\n case 0: invert = (x + y) % 2 === 0; break;\n case 1: invert = y % 2 === 0; break;\n case 2: invert = x % 3 === 0; break;\n case 3: invert = (x + y) % 3 === 0; break;\n case 4: invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0; break;\n case 5: invert = ((x * y) % 2) + ((x * y) % 3) === 0; break;\n case 6: invert = (((x * y) % 2) + ((x * y) % 3)) % 2 === 0; break;\n default: invert = (((x + y) % 2) + ((x * y) % 3)) % 2 === 0; break;\n }\n if (invert) {\n modules[y][x] = !modules[y][x];\n }\n }\n }\n}\n\n// \u2500\u2500 Mask penalty scoring (rules N1\u2013N4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction computePenalty(modules: boolean[][]): number {\n const size = modules.length;\n let penalty = 0;\n\n // N1: runs of \u22655 same-colour modules in a row/column.\n for (let y = 0; y < size; y++) {\n let runColor = false;\n let runLength = 0;\n for (let x = 0; x < size; x++) {\n if (x === 0 || modules[y][x] !== runColor) {\n runColor = modules[y][x];\n runLength = 1;\n } else {\n runLength++;\n if (runLength === 5) {\n penalty += 3;\n } else if (runLength > 5) {\n penalty += 1;\n }\n }\n }\n }\n for (let x = 0; x < size; x++) {\n let runColor = false;\n let runLength = 0;\n for (let y = 0; y < size; y++) {\n if (y === 0 || modules[y][x] !== runColor) {\n runColor = modules[y][x];\n runLength = 1;\n } else {\n runLength++;\n if (runLength === 5) {\n penalty += 3;\n } else if (runLength > 5) {\n penalty += 1;\n }\n }\n }\n }\n\n // N2: 2\u00D72 blocks of the same colour.\n for (let y = 0; y < size - 1; y++) {\n for (let x = 0; x < size - 1; x++) {\n const c = modules[y][x];\n if (c === modules[y][x + 1] && c === modules[y + 1][x] && c === modules[y + 1][x + 1]) {\n penalty += 3;\n }\n }\n }\n\n // N3: finder-like 1:1:3:1:1 patterns with 4-module light flank.\n const hasFinderPattern = (line: boolean[], start: number): number => {\n const core = [true, false, true, true, true, false, true];\n const matchesCore = core.every((value, index) => line[start + index] === value);\n if (!matchesCore) {\n return 0;\n }\n const lightBefore = start >= 4 && line.slice(start - 4, start).every((v) => !v);\n const lightAfter = start + 11 <= line.length && line.slice(start + 7, start + 11).every((v) => !v);\n return (lightBefore ? 40 : 0) + (lightAfter ? 40 : 0);\n };\n\n for (let y = 0; y < size; y++) {\n const row = modules[y];\n const column = modules.map((r) => r[y]);\n for (let x = 0; x + 7 <= size; x++) {\n penalty += hasFinderPattern(row, x);\n penalty += hasFinderPattern(column, x);\n }\n }\n\n // N4: dark-module proportion deviation from 50%, in 5% steps.\n let dark = 0;\n for (const row of modules) {\n for (const module of row) {\n if (module) {\n dark++;\n }\n }\n }\n const total = size * size;\n const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;\n penalty += k * 10;\n\n return penalty;\n}\n\n// \u2500\u2500 SVG rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Options for {@link qrToSvg}. */\nexport interface QrSvgOptions {\n /** Dark module colour. @default '#000000' */\n dark?: string;\n\n /** Light/background colour; `'transparent'` is allowed. @default '#ffffff' */\n light?: string;\n\n /** Quiet-zone width in modules on each side. @default 2 */\n quietZone?: number;\n}\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\n/**\n * Renders an encoded symbol as a crisp, scalable `<svg>` element. One\n * `<path>` carries all dark modules so the output stays compact.\n *\n * Built with `createElementNS`/`setAttribute` rather than markup strings so\n * caller-supplied colours can never be interpreted as HTML (CodeQL\n * js/html-constructed-from-input). Append the returned element directly;\n * never serialize it back through `innerHTML`.\n */\nexport function qrToSvg(qr: QrCode, options: QrSvgOptions = {}): SVGSVGElement {\n const dark = options.dark ?? '#000000';\n const light = options.light ?? '#ffffff';\n const quietZone = options.quietZone ?? 2;\n const dimension = qr.size + quietZone * 2;\n\n let path = '';\n for (let y = 0; y < qr.size; y++) {\n for (let x = 0; x < qr.size; x++) {\n if (qr.modules[y][x]) {\n path += `M${x + quietZone} ${y + quietZone}h1v1h-1z`;\n }\n }\n }\n\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('viewBox', `0 0 ${dimension} ${dimension}`);\n svg.setAttribute('shape-rendering', 'crispEdges');\n svg.setAttribute('role', 'img');\n\n const rect = document.createElementNS(SVG_NS, 'rect');\n rect.setAttribute('width', String(dimension));\n rect.setAttribute('height', String(dimension));\n rect.setAttribute('fill', light);\n svg.appendChild(rect);\n\n const modules = document.createElementNS(SVG_NS, 'path');\n modules.setAttribute('d', path);\n modules.setAttribute('fill', dark);\n svg.appendChild(modules);\n\n return svg;\n}\n", "/**\n * Wallet discovery via the `/.well-known/enbox-connect` document.\n *\n * Shared by the connect modal (relay discovery + custom-URL validation)\n * and exported for dapps rolling their own wallet selection UI.\n *\n * @module\n */\n\n/** Path of the wallet's connect discovery document, relative to its origin. */\nexport const WALLET_WELL_KNOWN_PATH = '/.well-known/enbox-connect';\n\n/** Timeout applied to the well-known validation fetch. */\nconst WELL_KNOWN_FETCH_TIMEOUT_MS = 6_000;\n\n/** The wallet's `/.well-known/enbox-connect` discovery document. */\nexport interface WalletWellKnownDocument {\n /** Base URL of the relay that brokers this wallet's remote connects. */\n connectServerUrl: string;\n}\n\n/**\n * Fetch a wallet's `/.well-known/enbox-connect` discovery document.\n *\n * Resolves the parsed document when it is reachable and names a\n * `connectServerUrl`; resolves `undefined` for unreachable origins, non-2xx\n * responses, CORS failures, and malformed documents.\n */\nexport async function fetchWalletWellKnown(origin: string): Promise<WalletWellKnownDocument | undefined> {\n try {\n const wellKnownUrl = new URL(WALLET_WELL_KNOWN_PATH, origin).toString();\n const response = await fetch(wellKnownUrl, { signal: AbortSignal.timeout(WELL_KNOWN_FETCH_TIMEOUT_MS) });\n if (!response.ok) {\n return undefined;\n }\n\n const payload = await response.json() as { connectServerUrl?: unknown } | null;\n if (typeof payload?.connectServerUrl !== 'string') {\n return undefined;\n }\n return { connectServerUrl: payload.connectServerUrl };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Fetch a wallet's `/.well-known/enbox-connect` discovery document to confirm\n * the origin hosts an Enbox-compatible wallet.\n *\n * Resolves `true` only when the document is reachable and names a\n * `connectServerUrl`. Unreachable origins, non-2xx responses, CORS failures,\n * and malformed documents resolve `false`.\n */\nexport async function probeWalletWellKnown(origin: string): Promise<boolean> {\n return (await fetchWalletWellKnown(origin)) !== undefined;\n}\n", "/**\n * Relay connect runner \u2014 the dapp side of the QR/deep-link connect flow,\n * with interactive PIN retry.\n *\n * This mirrors the `@enbox/connect` kernel `ConnectClient` step-for-step and\n * is composed entirely from the kernel's exported primitives (`sealRequest`,\n * `openResponse`, `RelayClientTransport`); no cryptography is reimplemented\n * here. It exists as a separate orchestrator for one reason the kernel\n * client cannot express today: **PIN retry against the delivered response**.\n * `ConnectClient` collects the PIN once and opens the response once, so a\n * mistyped code fails the whole handshake \u2014 the wallet user would have to\n * scan and approve again. The connect modal instead keeps the sealed\n * response and re-runs `openResponse` per attempt, which is safe because\n * opening is a pure decrypt-and-verify step.\n *\n * If the kernel later grows a PIN-attempts seam, this module collapses into\n * `ConnectClient` usage.\n *\n * @module\n */\n\nimport type { Jwk } from '@enbox/crypto';\nimport type { PortableDid } from '@enbox/dids';\nimport type {\n ConnectClientMetadata,\n ConnectPermissionRequest,\n ConnectRequest,\n ConnectRequestType,\n ConnectResult,\n WalletUriHandoff,\n} from '@enbox/connect';\n\nimport { DidJwk } from '@enbox/dids';\nimport { X25519 } from '@enbox/crypto';\nimport {\n CONNECT_DENIED_TOKEN,\n openResponse,\n randomToken,\n RelayClientTransport,\n resolveDelegatePortableDid,\n sealRequest,\n} from '@enbox/connect';\n\n/** Maximum interactive PIN attempts before the handshake fails. */\nexport const MAX_PIN_ATTEMPTS = 6;\n\n/** Thrown internally when a relay handshake is cancelled by the UI. */\nexport class RelayConnectCancelledError extends Error {\n constructor() {\n super('[@enbox/browser] Relay connect cancelled.');\n this.name = 'RelayConnectCancelledError';\n }\n}\n\n/** Options for {@link runRelayConnect}. */\nexport interface RelayConnectOptions {\n /** Relay base URL (the wallet's `connectServerUrl`). */\n connectServerUrl: string;\n\n /** Wallet URI the request pointer is attached to (QR / deep-link target). */\n walletUri: string;\n\n /** The user-friendly name of the app, shown in the wallet consent UI. */\n appName: string;\n\n /** Optional icon URL for the app, shown in the wallet consent UI. */\n appIcon?: string;\n\n /** Optional client/environment metadata for wallet session display. */\n clientMetadata?: ConnectClientMetadata;\n\n /** DWN protocols and permission scopes being requested. */\n permissionRequests: ConnectPermissionRequest[];\n\n /** Existing delegate credentials reused by a refresh request. */\n delegatePortableDid?: PortableDid;\n\n /** User-facing request purpose. Absent means a normal connect. */\n requestType?: ConnectRequestType;\n\n /** Total milliseconds to poll the relay for a wallet response. */\n timeoutMs?: number;\n\n /** Milliseconds between relay polling attempts. */\n pollIntervalMs?: number;\n\n /**\n * Receives the wallet URI handoff (with the request pointer TTL) as soon\n * as the request is delivered \u2014 render it as a QR code or deep link.\n */\n onWalletUriReady: (handoff: WalletUriHandoff) => void;\n\n /**\n * Collects one PIN attempt from the user. Called again (with the attempt\n * number, 1-based, and the previous failure) after a wrong code, up to\n * {@link MAX_PIN_ATTEMPTS} times.\n */\n requestPin: (attempt: number, previousError?: Error) => Promise<string>;\n\n /**\n * Cancellation signal: when it settles, polling stops and the handshake\n * rejects with {@link RelayConnectCancelledError}.\n */\n cancelled?: Promise<never> | undefined;\n\n /**\n * Invoked once when the relay reports the wallet has claimed (fetched)\n * the pushed request \u2014 the app can show \"phone connected\" progress.\n */\n onClaimed?: () => void;\n\n /** Transport factory override (tests). */\n createTransport?: (options: {\n connectServerUrl: string;\n walletUri: string;\n timeoutMs?: number;\n pollIntervalMs?: number;\n onClaimed?: () => void;\n }) => Pick<RelayClientTransport, 'requestProfile' | 'deliverRequest' | 'awaitResponse' | 'requiresPin'>\n & Partial<Pick<RelayClientTransport, 'confirmComplete'>>;\n}\n\n/**\n * Sleep used between relay polls that ends early when the page returns to\n * the foreground. Browsers throttle \u2014 and mobile browsers freeze \u2014 timers in\n * background tabs, so a plain interval sleep can leave the user staring at a\n * stale stage after approving in the wallet tab; cutting the sleep short on\n * `visibilitychange` makes the next poll (and with it the pairing-code\n * prompt) land the moment they switch back. Falls back to a plain sleep\n * outside DOM environments.\n */\nexport function visibilityAwareSleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n if (typeof document === 'undefined') {\n setTimeout(resolve, ms);\n return;\n }\n\n const finish = (): void => {\n clearTimeout(timer);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n resolve();\n };\n const onVisibilityChange = (): void => {\n if (document.visibilityState === 'visible') {\n finish();\n }\n };\n const timer = setTimeout(finish, ms);\n document.addEventListener('visibilitychange', onVisibilityChange);\n });\n}\n\n/**\n * Runs one relay-mediated connect handshake end-to-end and returns the\n * delegated credentials, or `undefined` when the user denied in the wallet.\n */\nexport async function runRelayConnect(options: RelayConnectOptions): Promise<ConnectResult | undefined> {\n if (options.requestType === 'refresh' && options.delegatePortableDid === undefined) {\n throw new Error('Connect: refresh requests require an existing `delegatePortableDid`.');\n }\n\n const createTransport = options.createTransport\n ?? ((transportOptions): RelayClientTransport => new RelayClientTransport({\n ...transportOptions,\n sleep: visibilityAwareSleep,\n }));\n\n const transport = createTransport({\n connectServerUrl : options.connectServerUrl,\n walletUri : options.walletUri,\n timeoutMs : options.timeoutMs,\n pollIntervalMs : options.pollIntervalMs,\n onClaimed : options.onClaimed,\n });\n\n // Ephemeral client DID for request signing and response addressing, and a\n // fresh X25519 pair the wallet seals the response to \u2014 same shape as the\n // kernel `ConnectClient`.\n const clientDid = await DidJwk.create();\n const responsePrivateKey = await X25519.generateKey();\n const responsePublicKey: Jwk = { kty: 'OKP', crv: 'X25519', x: responsePrivateKey.x };\n\n const nonce = randomToken();\n const state = randomToken();\n\n const profile = await transport.requestProfile(state);\n\n const request: ConnectRequest = {\n clientDid : clientDid.uri,\n appName : options.appName,\n appIcon : options.appIcon,\n clientMetadata : options.clientMetadata,\n permissionRequests : options.permissionRequests,\n delegateDid : options.delegatePortableDid?.uri,\n requestType : options.requestType,\n supportedDidMethods : ['did:dht', 'did:jwk'],\n nonce,\n state,\n responseKey : responsePublicKey,\n reply : profile.reply,\n };\n\n const requestJwe = await sealRequest({ request, signer: clientDid, encryption: profile.encryption });\n\n const handoff = await transport.deliverRequest(requestJwe);\n if (handoff !== undefined) {\n options.onWalletUriReady(handoff);\n }\n\n const race = options.cancelled === undefined\n ? transport.awaitResponse()\n : Promise.race([transport.awaitResponse(), options.cancelled]);\n\n const responseCiphertext = await race;\n if (responseCiphertext === CONNECT_DENIED_TOKEN) {\n return undefined;\n }\n\n // Interactive PIN loop: opening is a pure decrypt-and-verify step, so a\n // wrong code costs one more attempt, not a whole new wallet approval.\n // Errors raised by the kernel's value checks carry a 'Connect:' prefix and\n // indicate a protocol violation, not a mistyped code \u2014 those fail closed.\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= MAX_PIN_ATTEMPTS; attempt++) {\n const pin = await (options.cancelled === undefined\n ? options.requestPin(attempt, lastError)\n : Promise.race([options.requestPin(attempt, lastError), options.cancelled]));\n\n try {\n const response = await openResponse({\n jwe : responseCiphertext,\n recipientPrivateKey : responsePrivateKey,\n expected : { clientDid: clientDid.uri, nonce, state },\n pin,\n });\n\n const delegatePortableDid = resolveDelegatePortableDid({\n localDelegatePortableDid: options.delegatePortableDid,\n response,\n });\n\n // Best-effort completion signal so the wallet can flip its pairing\n // screen to a confirmed \"connected\" state instead of leaving the user\n // to dismiss it blind. Fire-and-forget \u2014 mirrors the kernel client.\n void transport.confirmComplete?.().catch((): undefined => undefined);\n\n return {\n delegatePortableDid,\n delegateGrants : response.delegateGrants,\n connectedDid : response.providerDid,\n sessionRevocations : response.sessionRevocations,\n };\n } catch (error) {\n const failure = error instanceof Error ? error : new Error(String(error));\n if (failure.message.startsWith('Connect:')) {\n // Structural/value-check failure \u2014 retrying the PIN cannot help.\n throw failure;\n }\n lastError = failure;\n }\n }\n\n throw new Error(`[@enbox/browser] The pairing code did not match after ${MAX_PIN_ATTEMPTS} attempts.`);\n}\n", "/**\n * Browser connect handler for `@enbox/auth`.\n *\n * Implements the {@link ConnectHandler} interface using browser-native\n * DWeb Connect (popup + postMessage) with a wallet selector modal.\n *\n * @module\n */\n\nimport type { PortableDid } from '@enbox/dids';\nimport type { ConnectHandler, ConnectResult } from '@enbox/auth';\nimport type { ConnectPermissionRequest, ConnectRequestType } from '@enbox/connect';\n\nimport { runConnectModal } from './ui/connect-modal.js';\n\nimport type { ConnectMethod, ConnectModalTheme } from './ui/connect-modal.js';\n\n/** A wallet entry shown in the wallet selector modal. */\nexport interface WalletOption {\n /** Display name (e.g. \"Enbox\"). */\n name: string;\n\n /** Base URL of the wallet app (e.g. \"https://enbox-wallet.pages.dev\"). */\n url: string;\n\n /** Optional icon URL. If omitted, the wallet's favicon is used. */\n icon?: string;\n\n /** Short description shown below the wallet name in the selector. */\n description?: string;\n}\n\n/** Default wallets shown in the selector when no overrides are provided. */\nexport const DEFAULT_WALLETS: WalletOption[] = [\n {\n name : 'Enbox',\n url : 'https://enbox-wallet.pages.dev',\n description : 'Manage your digital identity and data',\n },\n {\n name : 'Prism',\n url : 'https://prism-wallet.pages.dev',\n description : 'A clear view into your digital identity',\n },\n {\n name : 'Matcha',\n url : 'https://matcha-wallet.pages.dev',\n description : 'A fresh approach to digital identity',\n },\n {\n name : 'Onyx',\n url : 'https://onyx-wallet.pages.dev',\n description : 'A refined home for your digital identity',\n },\n {\n name : 'Taffy',\n url : 'https://taffy-wallet.pages.dev',\n description : 'A playful take on your digital identity',\n },\n {\n name : 'Astoria',\n url : 'https://astoria-wallet.pages.dev',\n description : 'A grand home for your digital identity',\n },\n];\n\n/** Options for creating a BrowserConnectHandler. */\nexport interface BrowserConnectHandlerOptions {\n /**\n * Known wallets shown in the wallet selector modal.\n * If omitted, {@link DEFAULT_WALLETS} is used.\n */\n wallets?: WalletOption[];\n\n /**\n * Explicit wallet URL. If provided, the wallet selector is skipped\n * and this URL is used directly.\n */\n walletUrl?: string;\n\n /**\n * Timeout in milliseconds for the wallet popup flow.\n * @default 300_000 (5 minutes)\n */\n timeout?: number;\n\n /**\n * Display name of the requesting application.\n * Shown in the wallet's permission consent screen.\n */\n appName?: string;\n\n /**\n * Icon URL of the requesting application.\n * Shown alongside the app name in the wallet's consent screen.\n * Defaults to `${window.location.origin}/favicon.ico` if omitted.\n */\n appIcon?: string;\n\n /**\n * Preferred connect method on open: `'phone'` (QR / deep link via the\n * relay) or `'browser'` (wallet popup on this device). Overrides the\n * remembered choice.\n * @default 'phone'\n */\n preferredMethod?: ConnectMethod;\n\n /**\n * Remember the successful method + wallet in localStorage and pre-shape\n * the next connect session accordingly.\n * @default true\n */\n rememberChoice?: boolean;\n\n /**\n * Relay base URL override for the phone path. When omitted, each wallet's\n * `connectServerUrl` is discovered from its `/.well-known/enbox-connect`\n * document.\n */\n connectServerUrl?: string;\n\n /**\n * Path appended to the wallet origin to form the phone path's QR /\n * deep-link target.\n * @default '/connect/app'\n */\n relayWalletPath?: string;\n\n /**\n * Color scheme for the connect modal. By default it follows the\n * visitor's system light/dark appearance; apps can force an appearance\n * and/or override palette tokens (accent, surfaces, text) per scheme to\n * match their brand.\n */\n theme?: ConnectModalTheme;\n}\n\n/**\n * Create a browser-native connect handler over the connect modal.\n *\n * The modal owns the whole session on one surface: the phone path (a QR /\n * deep link over the relay, with pairing-code entry) is the default, the\n * in-browser wallet popup is the alternate, and the wallet catalog plus\n * custom-URL entry live in a disclosure. It resolves with the delegate\n * credentials on success and `undefined` when the user denies.\n *\n * @example\n * ```ts\n * import { AuthManager, BrowserConnectHandler } from '@enbox/browser';\n *\n * const auth = await AuthManager.create({\n * connectHandler: BrowserConnectHandler({\n * appName: 'My Dapp',\n * }),\n * });\n *\n * const session = await auth.connect({ protocols: [NotesProtocol] });\n * ```\n */\nexport function BrowserConnectHandler(\n options: BrowserConnectHandlerOptions = {},\n): ConnectHandler {\n const {\n wallets = DEFAULT_WALLETS,\n walletUrl,\n timeout,\n appName,\n appIcon,\n preferredMethod,\n rememberChoice,\n connectServerUrl,\n relayWalletPath,\n theme,\n } = options;\n\n return {\n async requestAccess(params: {\n permissionRequests: ConnectPermissionRequest[];\n delegatePortableDid?: PortableDid;\n requestType?: ConnectRequestType;\n }): Promise<ConnectResult | undefined> {\n return runConnectModal({\n wallets,\n walletUrl,\n preferredMethod,\n rememberChoice,\n appName,\n appIcon : appIcon ?? `${window.location.origin}/favicon.ico`,\n connectServerUrl,\n relayWalletPath,\n timeout,\n theme,\n mode : params.requestType,\n delegatePortableDid : params.delegatePortableDid,\n permissionRequests : params.permissionRequests,\n });\n },\n };\n}\n", "/**\n * DWeb Connect wallet transport \u2014 the wallet side of the popup/postMessage\n * connect flow, exported for wallet apps (e.g. the Enbox web wallet).\n *\n * A wallet's `/dweb-connect` page creates one transport per session:\n *\n * 1. `create()` generates a fresh ephemeral X25519 key pair and emits the\n * `loaded` beacon (public key + wallet origin) to the opener window with a\n * pinned `targetOrigin`.\n * 2. `awaitRequest()` receives the sealed request ciphertext and opens it via\n * the `@enbox/connect` kernel (`ConnectProvider.openRequest`), which\n * value-checks the `apv` origin binding against this wallet's origin.\n * 3. After the consent ceremony, the wallet posts the sealed response JWE via\n * `sendResponse()` \u2014 or the deny token via `deny()` \u2014 back to the opener,\n * again with a pinned `targetOrigin`. `sendResponseAwaitingAck()` does the\n * same but stays alive briefly for the dapp's completion ack, so the\n * wallet can show a confirmed \"connected\" state before closing itself.\n *\n * The dapp origin is never assumed: it is taken from an explicit option or\n * derived from `document.referrer`, and `create()` fails when neither is\n * available. `'*'` is never used as a `targetOrigin`.\n *\n * @module\n */\n\nimport type { ConnectRequest } from '@enbox/connect';\nimport type { Jwk } from '@enbox/crypto';\n\nimport { X25519 } from '@enbox/crypto';\nimport { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';\n\nimport {\n DWEB_CONNECT_ACK_MESSAGE_TYPE,\n DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n DWEB_CONNECT_REQUEST_MESSAGE_TYPE,\n DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n getTrustedMessage,\n} from './dweb-connect-messages.js';\n\n/** Default budget for awaiting the dapp's sealed request. */\nconst DEFAULT_REQUEST_TIMEOUT_MS = 300_000;\n\n/** Default budget for awaiting the dapp's completion ack after a response. */\nconst DEFAULT_ACK_TIMEOUT_MS = 5_000;\n\n/** Options for creating a {@link WalletPostMessageTransport}. */\nexport type WalletPostMessageTransportOptions = {\n /**\n * Origin of the dapp that opened this wallet popup. When omitted, it is\n * derived from `document.referrer`; creation fails when neither is\n * available \u2014 the transport never falls back to `'*'`.\n */\n dappOrigin?: string;\n\n /**\n * The dapp window to exchange messages with.\n * @default window.opener\n */\n dappWindow?: Window;\n\n /**\n * Budget in milliseconds for awaiting the dapp's sealed request.\n * @default 300_000 (5 minutes)\n */\n timeoutMs?: number;\n};\n\n/**\n * Wallet-side postMessage transport for the DWeb Connect popup flow.\n *\n * Security properties:\n * - `targetOrigin` of every outbound `postMessage` (beacon and response) is\n * pinned to the dapp origin \u2014 never `'*'`.\n * - Inbound messages are dropped unless `event.origin` equals the pinned dapp\n * origin AND `event.source` is the dapp window.\n * - The ephemeral X25519 private key never leaves the transport; the request\n * JWE is opened by the kernel with the `apv` header value-checked against\n * this wallet's own origin.\n */\nexport class WalletPostMessageTransport {\n private readonly _dappOrigin: string;\n private readonly _dappWindow: Window;\n private readonly _recipientPrivateKey: Jwk;\n\n private _requestReceived = false;\n private _timeoutId?: ReturnType<typeof setTimeout>;\n private _messageListener?: (event: MessageEvent) => void;\n private _resolveAck?: (acked: boolean) => void;\n\n private readonly _requestPromise: Promise<ConnectRequest>;\n private _resolveRequest?: (request: ConnectRequest) => void;\n private _rejectRequest?: (error: Error) => void;\n\n private constructor(params: { dappOrigin: string; dappWindow: Window; recipientPrivateKey: Jwk; timeoutMs: number }) {\n this._dappOrigin = params.dappOrigin;\n this._dappWindow = params.dappWindow;\n this._recipientPrivateKey = params.recipientPrivateKey;\n\n this._requestPromise = new Promise<ConnectRequest>((resolve, reject): void => {\n this._resolveRequest = resolve;\n this._rejectRequest = reject;\n });\n // Mark early rejections (timeout before `awaitRequest()` is called) as\n // handled until the wallet attaches its own handlers.\n this._requestPromise.catch((): undefined => undefined);\n\n this._messageListener = (event: MessageEvent): void => { this.onMessage(event); };\n window.addEventListener('message', this._messageListener);\n\n this._timeoutId = setTimeout((): void => {\n this.close();\n this._rejectRequest?.(new Error('[@enbox/browser] Timed out waiting for the connect request from the dapp.'));\n }, params.timeoutMs);\n }\n\n /**\n * Creates the transport for one connect session: resolves and pins the dapp\n * origin, generates a fresh ephemeral X25519 key pair, starts listening for\n * the sealed request, and emits the `loaded` beacon to the dapp window.\n *\n * @throws If not in a browser, if no dapp window is available, or if the\n * dapp origin can neither be supplied nor derived from the referrer.\n */\n public static async create(options: WalletPostMessageTransportOptions = {}): Promise<WalletPostMessageTransport> {\n if (typeof window === 'undefined') {\n throw new Error('[@enbox/browser] WalletPostMessageTransport is only available in browser environments.');\n }\n\n const dappWindow = options.dappWindow ?? window.opener as Window | null;\n if (!dappWindow) {\n throw new Error('[@enbox/browser] No opener window: the DWeb Connect page must be opened as a popup by the dapp.');\n }\n\n const dappOrigin = resolveDappOrigin(options.dappOrigin);\n\n const recipientPrivateKey = await X25519.generateKey();\n const walletEpk: Jwk = { kty: 'OKP', crv: 'X25519', x: recipientPrivateKey.x };\n\n const transport = new WalletPostMessageTransport({\n dappOrigin,\n dappWindow,\n recipientPrivateKey,\n timeoutMs: options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,\n });\n\n // The listener is registered, so the beacon cannot race the request.\n dappWindow.postMessage({\n type : DWEB_CONNECT_LOADED_MESSAGE_TYPE,\n walletEpk,\n walletOrigin : globalThis.location.origin,\n }, dappOrigin);\n\n return transport;\n }\n\n /** The pinned origin of the dapp this transport exchanges messages with. */\n public get dappOrigin(): string {\n return this._dappOrigin;\n }\n\n /**\n * Awaits the dapp's sealed request and opens it via the kernel: ECDH-ES\n * decryption with this session's ephemeral key, `apv` value-checked against\n * this wallet's origin, JWT signature verification, and payload shape\n * assertion. Rejects on timeout, on an unopenable request, or when the\n * request does not use the `post_message` reply mode.\n */\n public async awaitRequest(): Promise<ConnectRequest> {\n return await this._requestPromise;\n }\n\n /**\n * Posts the sealed response JWE (or the deny token) back to the dapp window\n * with the `targetOrigin` pinned to the dapp origin, then closes the\n * transport.\n *\n * @param idToken - The sealed response JWE, or the literal deny token.\n */\n public sendResponse(idToken: string): void {\n this._dappWindow.postMessage({\n type : DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n payload : idToken,\n }, this._dappOrigin);\n this.close();\n }\n\n /**\n * Posts the sealed response JWE back to the dapp like\n * {@link sendResponse}, then keeps the channel open briefly for the dapp's\n * completion ack \u2014 the signal that it opened the response successfully \u2014\n * before closing the transport.\n *\n * Lets the wallet's connect page show a confirmed \"connected\" state (and\n * close itself with confidence) instead of asking the user to dismiss the\n * screen blind. Dapps predating the ack simply never send one, so the\n * wallet should keep a manual dismiss affordance for the `false` case.\n *\n * @param idToken - The sealed response JWE.\n * @param options - The awaiting options.\n * @param options.timeoutMs - Ack budget in milliseconds; defaults to 5 s.\n * @returns Whether the dapp acknowledged completion within the budget.\n */\n public async sendResponseAwaitingAck(idToken: string, options: { timeoutMs?: number } = {}): Promise<boolean> {\n const ackPromise = new Promise<boolean>((resolve): void => {\n this._resolveAck = resolve;\n });\n\n this._dappWindow.postMessage({\n type : DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,\n payload : idToken,\n }, this._dappOrigin);\n\n const ackTimeoutId = setTimeout((): void => {\n this._resolveAck?.(false);\n }, options.timeoutMs ?? DEFAULT_ACK_TIMEOUT_MS);\n\n const acked = await ackPromise;\n clearTimeout(ackTimeoutId);\n this._resolveAck = undefined;\n this.close();\n return acked;\n }\n\n /** Posts the deny token back to the dapp \u2014 the user rejected the request. */\n public deny(): void {\n this.sendResponse(CONNECT_DENIED_TOKEN);\n }\n\n /** Stops listening and releases the session's timers. Idempotent. */\n public close(): void {\n clearTimeout(this._timeoutId);\n if (this._messageListener !== undefined) {\n window.removeEventListener('message', this._messageListener);\n this._messageListener = undefined;\n }\n }\n\n private onMessage(event: MessageEvent): void {\n const message = getTrustedMessage(event, this._dappOrigin, this._dappWindow);\n if (message === undefined) { return; }\n\n if (message.type === DWEB_CONNECT_ACK_MESSAGE_TYPE) {\n this._resolveAck?.(true);\n return;\n }\n\n if (message.type !== DWEB_CONNECT_REQUEST_MESSAGE_TYPE || this._requestReceived) { return; }\n this._requestReceived = true;\n\n if (typeof message.jwe !== 'string') {\n this.settleRequest(new Error('[@enbox/browser] Connect request message did not carry a ciphertext payload.'));\n return;\n }\n\n void this.openRequest(message.jwe);\n }\n\n private async openRequest(jwe: string): Promise<void> {\n try {\n const request = await ConnectProvider.openRequest({\n jwe,\n decryption: {\n mode : 'ecdh-es',\n recipientPrivateKey : this._recipientPrivateKey,\n walletOrigin : globalThis.location.origin,\n },\n });\n\n if (request.reply.mode !== 'post_message') {\n this.settleRequest(new Error('[@enbox/browser] Connect request over the popup channel must use the `post_message` reply mode.'));\n return;\n }\n\n this.settleRequest(request);\n } catch (error) {\n this.settleRequest(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n private settleRequest(outcome: ConnectRequest | Error): void {\n clearTimeout(this._timeoutId);\n if (outcome instanceof Error) {\n this.close();\n this._rejectRequest?.(outcome);\n return;\n }\n this._resolveRequest?.(outcome);\n }\n}\n\n/**\n * Resolves the dapp origin to pin: the explicit option when provided,\n * otherwise the origin of `document.referrer`. Never falls back to `'*'`.\n */\nfunction resolveDappOrigin(explicitOrigin: string | undefined): string {\n if (explicitOrigin !== undefined) {\n return new URL(explicitOrigin).origin;\n }\n\n if (document.referrer) {\n return new URL(document.referrer).origin;\n }\n\n throw new Error(\n '[@enbox/browser] Unable to determine the dapp origin: no `dappOrigin` option was provided and `document.referrer` is empty.'\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["Enbox", "defineProtocol", "repository", "AuthManager", "AuthSession", "SESSION_EXPIRED_ERROR_CODE", "SESSION_REVOKED_ERROR_CODE", "computeConnectionStatus", "isSessionExpiredError", "isSessionInvalidError", "normalizeProtocolRequests", "WalletConnect", "CONNECT_DENIED_TOKEN", "ConnectProvider", "DidDht", "DidWeb", "UniversalResolver", "parseDrlUrl", "url", "idx", "prefix", "rest", "slashIdx", "didResolver", "UniversalResolver", "DidDht", "DidWeb", "httpToHttpsRegex", "trailingSlashRegex", "DRL_CACHE_NAME", "getDwnEndpoints", "did", "didDocument", "endpoints", "service", "url", "openDrlCache", "handleEvent", "event", "path", "options", "drl", "responseCache", "cachedResponse", "match", "cacheTime", "fetchResource", "response", "error", "lastError", "endpoint", "cacheResponse", "cache", "clonedResponse", "headers", "modifiedResponse", "installWorker", "workerSelf", "parsed", "parseDrlUrl", "installUrl", "loaderStyles", "tabContent", "elementsInjected", "overlayElement", "styleElement", "injectElements", "cancelNavigation", "removeElements", "activeNavigation", "linkFeaturesActive", "clickHandler", "pointerdownHandler", "addLinkFeatures", "anchor", "href", "openAsTab", "tab", "target", "resetContextMenuTarget", "contextMenuTarget", "removeLinkFeatures", "r", "activatePolyfills", "deactivatePolyfills", "clearDrlCache", "ConnectClient", "buildWalletIcon", "wallet", "wrap", "badge", "sources", "iconCandidates", "img", "index", "origin", "assertX25519PublicJwk", "CONNECT_DENIED_TOKEN", "ConnectClient", "DWEB_CONNECT_PATH", "DWEB_CONNECT_LOADED_MESSAGE_TYPE", "DWEB_CONNECT_REQUEST_MESSAGE_TYPE", "DWEB_CONNECT_RESPONSE_MESSAGE_TYPE", "DWEB_CONNECT_ACK_MESSAGE_TYPE", "getTrustedMessage", "event", "expectedOrigin", "expectedSource", "data", "DEFAULT_TIMEOUT_MS", "CLOSED_POLL_INTERVAL_MS", "CLOSED_RESPONSE_GRACE_MS", "POPUP_WINDOW_NAME", "POPUP_WIDTH", "POPUP_HEIGHT", "popupWindowFeatures", "base", "openerWidth", "openerHeight", "left", "top", "assertBrowserEnvironment", "PopupWindowClosedError", "PopupClientTransport", "options", "popupUrl", "DWEB_CONNECT_PATH", "popup", "resolve", "reject", "event", "state", "jwe", "DWEB_CONNECT_REQUEST_MESSAGE_TYPE", "DWEB_CONNECT_ACK_MESSAGE_TYPE", "message", "getTrustedMessage", "DWEB_CONNECT_LOADED_MESSAGE_TYPE", "DWEB_CONNECT_RESPONSE_MESSAGE_TYPE", "walletEpk", "assertX25519PublicJwk", "CONNECT_DENIED_TOKEN", "error", "collectBrowserClientMetadata", "resolvedOptions", "languages", "language", "connectViaPopup", "transport", "client", "ConnectClient", "ECC_PER_BLOCK", "NUM_BLOCKS", "TOTAL_CODEWORDS", "FORMAT_ECL_M", "MAX_VERSION", "dataCodewords", "version", "encodeQr", "text", "forcedMask", "data", "candidate", "capacityBits", "bits", "pushBits", "value", "length", "i", "byte", "padBytes", "codewords", "allCodewords", "buildInterleavedCodewords", "size", "modules", "isFunction", "drawFunctionPatterns", "drawCodewords", "mask", "bestPenalty", "applyMask", "drawFormatBits", "penalty", "computePenalty", "numBlocks", "eccLen", "totalCodewords", "numShortBlocks", "shortBlockLen", "blocks", "eccBlocks", "rsDivisor", "reedSolomonDivisor", "offset", "dataLen", "block", "reedSolomonRemainder", "result", "index", "maxDataLen", "b", "gfMultiply", "x", "y", "z", "degree", "root", "j", "divisor", "factor", "ALIGNMENT_POSITIONS", "setFunctionModule", "dark", "drawFinderPattern", "positions", "drawAlignmentPattern", "drawVersionBits", "cx", "cy", "dy", "dx", "distance", "rem", "bit", "a", "bitIndex", "right", "vertical", "invert", "runColor", "runLength", "c", "hasFinderPattern", "line", "start", "lightBefore", "v", "lightAfter", "row", "column", "r", "module", "total", "k", "SVG_NS", "qrToSvg", "qr", "options", "light", "quietZone", "dimension", "path", "svg", "rect", "WALLET_WELL_KNOWN_PATH", "fetchWalletWellKnown", "origin", "wellKnownUrl", "WALLET_WELL_KNOWN_PATH", "response", "payload", "probeWalletWellKnown", "DidJwk", "X25519", "CONNECT_DENIED_TOKEN", "openResponse", "randomToken", "RelayClientTransport", "resolveDelegatePortableDid", "sealRequest", "MAX_PIN_ATTEMPTS", "RelayConnectCancelledError", "visibilityAwareSleep", "ms", "resolve", "finish", "timer", "onVisibilityChange", "runRelayConnect", "options", "transport", "transportOptions", "clientDid", "responsePrivateKey", "responsePublicKey", "nonce", "state", "profile", "request", "requestJwe", "handoff", "responseCiphertext", "lastError", "attempt", "pin", "response", "delegatePortableDid", "error", "failure", "LAST_CHOICE_STORAGE_KEY", "REMINT_SAFETY_MS", "REMINT_MIN_MS", "PIN_LENGTH", "WALLET_SEARCH_THRESHOLD", "WALLET_ROW_SIZE", "PALETTE_TOKENS", "discoverWalletConnectServerUrl", "walletOrigin", "fetchWalletWellKnown", "runPopupConnect", "options", "transport", "PopupClientTransport", "ConnectClient", "collectBrowserClientMetadata", "defaultIsMobile", "defaultDeps", "runRelayConnect", "probeWalletWellKnown", "readLastChoice", "storage", "raw", "parsed", "isValidRememberedWalletUrl", "writeLastChoice", "choice", "createRelaySession", "cancel", "session", "cancelled", "_", "reject", "RelayConnectCancelledError", "runConnectModal", "deps", "wallets", "dedupeWalletsByUrl", "rememberChoice", "appName", "relayWalletPath", "isMobile", "refreshing", "lastChoice", "rememberedWalletUrl", "walletInCatalog", "lockedWallet", "walletUrl", "method", "resolve", "host", "shadow", "style", "MODAL_STYLES", "overlay", "modal", "title", "theme", "appearance", "systemDark", "hasPaletteOverrides", "applyPaletteTokens", "scheme", "palette", "key", "value", "onSchemeChange", "settled", "relaySession", "remintTimer", "remintAt", "popupBusy", "pinResolve", "discoveryCache", "rowWallets", "walletByUrl", "url", "wallet", "hostnameOf", "composeWalletRow", "selected", "selectWallet", "renderFooter", "startMethod", "cleanup", "clearRemint", "onKeydown", "onVisibilityReturn", "settle", "settler", "succeed", "result", "renderConnected", "cancelModal", "buildHeader", "stage", "footer", "setStage", "nodes", "renderBusy", "message", "el", "morphToAway", "walletName", "renderAway", "buildHandoffLink", "handoff", "className", "link", "renderQr", "qrLink", "qrToSvg", "encodeQr", "logo", "buildWalletIcon", "stageLinkButton", "startPhone", "renderClaimed", "pulse", "renderPin", "attempt", "previousError", "resolvePin", "boxes", "inputs", "i", "input", "submitIfComplete", "code", "resolveOnce", "index", "event", "digits", "digit", "digitIndex", "check", "renderDenied", "stageButton", "renderError", "error", "renderPhoneUnavailable", "startPopup", "popupSurface", "renderPopupPrompt", "renderPopupWaiting", "renderPopupInterrupted", "blocked", "switchMethod", "renderPopupFailure", "failure", "popupBlocked", "PopupWindowClosedError", "resolveConnectServerUrl", "origin", "cached", "remintNow", "scheduleRemint", "expiresInSeconds", "delay", "connectServerUrl", "next", "switcher", "buildWalletSwitcher", "row", "alt", "tile", "isSelected", "panel", "gridWallets", "shown", "more", "updateScrollHint", "label", "tiles", "empty", "search", "query", "visible", "match", "scrollWrap", "scroll", "grid", "overflowing", "atEnd", "tileName", "custom", "go", "urlError", "allowUnverified", "submitCustom", "valid", "e", "trapFocus", "candidate", "tag", "text", "node", "onClick", "button", "titleText", "appIcon", "onCancel", "header", "identity", "icon", "closeBtn", "focusables", "first", "last", "active", "LIGHT_TOKENS", "DARK_TOKENS", "DEFAULT_WALLETS", "BrowserConnectHandler", "options", "wallets", "walletUrl", "timeout", "appName", "appIcon", "preferredMethod", "rememberChoice", "connectServerUrl", "relayWalletPath", "theme", "params", "runConnectModal", "X25519", "CONNECT_DENIED_TOKEN", "ConnectProvider", "DEFAULT_REQUEST_TIMEOUT_MS", "DEFAULT_ACK_TIMEOUT_MS", "WalletPostMessageTransport", "_WalletPostMessageTransport", "params", "resolve", "reject", "event", "options", "dappWindow", "dappOrigin", "resolveDappOrigin", "recipientPrivateKey", "X25519", "walletEpk", "transport", "DWEB_CONNECT_LOADED_MESSAGE_TYPE", "idToken", "DWEB_CONNECT_RESPONSE_MESSAGE_TYPE", "ackPromise", "ackTimeoutId", "acked", "CONNECT_DENIED_TOKEN", "message", "getTrustedMessage", "DWEB_CONNECT_ACK_MESSAGE_TYPE", "DWEB_CONNECT_REQUEST_MESSAGE_TYPE", "jwe", "request", "ConnectProvider", "error", "outcome", "explicitOrigin", "TypedRecord", "BrowserStorage", "DwnInterface", "DateSort", "DwnInterfaceName", "DwnMethodName"]
7
7
  }