@tatchi-xyz/sdk 0.17.0 → 0.18.0

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.
Files changed (122) hide show
  1. package/dist/cjs/core/EmailRecovery/emailRecoveryPendingStore.js +69 -0
  2. package/dist/cjs/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  3. package/dist/cjs/core/EmailRecovery/index.js +32 -20
  4. package/dist/cjs/core/EmailRecovery/index.js.map +1 -1
  5. package/dist/cjs/core/TatchiPasskey/emailRecovery.js +519 -448
  6. package/dist/cjs/core/TatchiPasskey/emailRecovery.js.map +1 -1
  7. package/dist/cjs/core/TatchiPasskey/index.js +1 -0
  8. package/dist/cjs/core/TatchiPasskey/index.js.map +1 -1
  9. package/dist/cjs/core/TatchiPasskey/relay.js +23 -1
  10. package/dist/cjs/core/TatchiPasskey/relay.js.map +1 -1
  11. package/dist/cjs/core/WalletIframe/client/IframeTransport.js +0 -7
  12. package/dist/cjs/core/WalletIframe/client/IframeTransport.js.map +1 -1
  13. package/dist/cjs/core/WalletIframe/client/router.js +6 -2
  14. package/dist/cjs/core/WalletIframe/client/router.js.map +1 -1
  15. package/dist/cjs/core/rpcCalls.js +8 -0
  16. package/dist/cjs/core/rpcCalls.js.map +1 -1
  17. package/dist/cjs/index.js +6 -2
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/react/components/AccountMenuButton/{LinkedDevicesModal-B6api181.css → LinkedDevicesModal-CSSowiHP.css} +1 -1
  20. package/dist/{esm/react/components/AccountMenuButton/LinkedDevicesModal-B6api181.css.map → cjs/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map} +1 -1
  21. package/dist/cjs/react/components/AccountMenuButton/{ProfileDropdown-B-DrG_u5.css → ProfileDropdown-CEPMZ1gY.css} +1 -1
  22. package/dist/{esm/react/components/AccountMenuButton/ProfileDropdown-B-DrG_u5.css.map → cjs/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map} +1 -1
  23. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css → Web3AuthProfileButton-DopOg7Xc.css} +1 -1
  24. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css.map → Web3AuthProfileButton-DopOg7Xc.css.map} +1 -1
  25. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css → TouchIcon-BQWentvJ.css} +1 -1
  26. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css.map → TouchIcon-BQWentvJ.css.map} +1 -1
  27. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css → PasskeyAuthMenu-DwrzWMYx.css} +1 -1
  28. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css.map → PasskeyAuthMenu-DwrzWMYx.css.map} +1 -1
  29. package/dist/cjs/react/components/{ShowQRCode-nZhZSaba.css → ShowQRCode-CCN4h6Uv.css} +1 -1
  30. package/dist/cjs/react/components/{ShowQRCode-nZhZSaba.css.map → ShowQRCode-CCN4h6Uv.css.map} +1 -1
  31. package/dist/cjs/react/hooks/usePreconnectWalletAssets.js +27 -32
  32. package/dist/cjs/react/hooks/usePreconnectWalletAssets.js.map +1 -1
  33. package/dist/cjs/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js +69 -0
  34. package/dist/cjs/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  35. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js +32 -20
  36. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  37. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js +519 -448
  38. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  39. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js +1 -0
  40. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  41. package/dist/cjs/react/sdk/src/core/TatchiPasskey/relay.js +23 -1
  42. package/dist/cjs/react/sdk/src/core/TatchiPasskey/relay.js.map +1 -1
  43. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js +0 -7
  44. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  45. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js +6 -2
  46. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  47. package/dist/cjs/react/sdk/src/core/rpcCalls.js +8 -0
  48. package/dist/cjs/react/sdk/src/core/rpcCalls.js.map +1 -1
  49. package/dist/esm/core/EmailRecovery/emailRecoveryPendingStore.js +63 -0
  50. package/dist/esm/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  51. package/dist/esm/core/EmailRecovery/index.js +28 -21
  52. package/dist/esm/core/EmailRecovery/index.js.map +1 -1
  53. package/dist/esm/core/TatchiPasskey/emailRecovery.js +519 -448
  54. package/dist/esm/core/TatchiPasskey/emailRecovery.js.map +1 -1
  55. package/dist/esm/core/TatchiPasskey/index.js +2 -1
  56. package/dist/esm/core/TatchiPasskey/index.js.map +1 -1
  57. package/dist/esm/core/TatchiPasskey/relay.js +23 -1
  58. package/dist/esm/core/TatchiPasskey/relay.js.map +1 -1
  59. package/dist/esm/core/WalletIframe/client/IframeTransport.js +0 -7
  60. package/dist/esm/core/WalletIframe/client/IframeTransport.js.map +1 -1
  61. package/dist/esm/core/WalletIframe/client/router.js +7 -3
  62. package/dist/esm/core/WalletIframe/client/router.js.map +1 -1
  63. package/dist/esm/core/rpcCalls.js +8 -1
  64. package/dist/esm/core/rpcCalls.js.map +1 -1
  65. package/dist/esm/index.js +4 -1
  66. package/dist/esm/index.js.map +1 -1
  67. package/dist/esm/react/components/AccountMenuButton/{LinkedDevicesModal-B6api181.css → LinkedDevicesModal-CSSowiHP.css} +1 -1
  68. package/dist/{cjs/react/components/AccountMenuButton/LinkedDevicesModal-B6api181.css.map → esm/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map} +1 -1
  69. package/dist/esm/react/components/AccountMenuButton/{ProfileDropdown-B-DrG_u5.css → ProfileDropdown-CEPMZ1gY.css} +1 -1
  70. package/dist/{cjs/react/components/AccountMenuButton/ProfileDropdown-B-DrG_u5.css.map → esm/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map} +1 -1
  71. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css → Web3AuthProfileButton-DopOg7Xc.css} +1 -1
  72. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css.map → Web3AuthProfileButton-DopOg7Xc.css.map} +1 -1
  73. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css → TouchIcon-BQWentvJ.css} +1 -1
  74. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css.map → TouchIcon-BQWentvJ.css.map} +1 -1
  75. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css → PasskeyAuthMenu-DwrzWMYx.css} +1 -1
  76. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css.map → PasskeyAuthMenu-DwrzWMYx.css.map} +1 -1
  77. package/dist/esm/react/components/{ShowQRCode-nZhZSaba.css → ShowQRCode-CCN4h6Uv.css} +1 -1
  78. package/dist/esm/react/components/{ShowQRCode-nZhZSaba.css.map → ShowQRCode-CCN4h6Uv.css.map} +1 -1
  79. package/dist/esm/react/hooks/usePreconnectWalletAssets.js +27 -32
  80. package/dist/esm/react/hooks/usePreconnectWalletAssets.js.map +1 -1
  81. package/dist/esm/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js +63 -0
  82. package/dist/esm/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  83. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js +28 -21
  84. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  85. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js +519 -448
  86. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  87. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js +2 -1
  88. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  89. package/dist/esm/react/sdk/src/core/TatchiPasskey/relay.js +23 -1
  90. package/dist/esm/react/sdk/src/core/TatchiPasskey/relay.js.map +1 -1
  91. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js +0 -7
  92. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  93. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js +7 -3
  94. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  95. package/dist/esm/react/sdk/src/core/rpcCalls.js +8 -1
  96. package/dist/esm/react/sdk/src/core/rpcCalls.js.map +1 -1
  97. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  98. package/dist/esm/sdk/{router-BLFegW7J.js → router-DuGYOd3G.js} +6 -9
  99. package/dist/esm/sdk/{rpcCalls-DEv9x5-f.js → rpcCalls-BQrJMTdg.js} +2 -2
  100. package/dist/esm/sdk/{rpcCalls-OhgEeFig.js → rpcCalls-YVeUVMk2.js} +8 -1
  101. package/dist/esm/sdk/wallet-iframe-host.js +624 -471
  102. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  103. package/dist/types/src/core/EmailRecovery/emailRecoveryPendingStore.d.ts +25 -0
  104. package/dist/types/src/core/EmailRecovery/emailRecoveryPendingStore.d.ts.map +1 -0
  105. package/dist/types/src/core/EmailRecovery/index.d.ts +1 -0
  106. package/dist/types/src/core/EmailRecovery/index.d.ts.map +1 -1
  107. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts +35 -6
  108. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts.map +1 -1
  109. package/dist/types/src/core/TatchiPasskey/index.d.ts +2 -2
  110. package/dist/types/src/core/TatchiPasskey/index.d.ts.map +1 -1
  111. package/dist/types/src/core/TatchiPasskey/relay.d.ts +2 -1
  112. package/dist/types/src/core/TatchiPasskey/relay.d.ts.map +1 -1
  113. package/dist/types/src/core/WalletIframe/client/IframeTransport.d.ts.map +1 -1
  114. package/dist/types/src/core/WalletIframe/client/router.d.ts +3 -3
  115. package/dist/types/src/core/WalletIframe/client/router.d.ts.map +1 -1
  116. package/dist/types/src/core/rpcCalls.d.ts +9 -0
  117. package/dist/types/src/core/rpcCalls.d.ts.map +1 -1
  118. package/dist/types/src/index.d.ts +1 -0
  119. package/dist/types/src/index.d.ts.map +1 -1
  120. package/dist/types/src/react/hooks/usePreconnectWalletAssets.d.ts.map +1 -1
  121. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  122. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"usePreconnectWalletAssets.js","names":["walletOriginOrigin: string | undefined"],"sources":["../../../../src/react/hooks/usePreconnectWalletAssets.ts"],"sourcesContent":["import React from 'react';\nimport type { TatchiContextProviderProps } from '../types';\nimport { setEmbeddedBase } from '../../core/sdkPaths';\n\n// Internal: Add preconnect/prefetch hints for wallet service + relayer and\n// expose an absolute embedded asset base for srcdoc iframes.\n//\n// What this hook does\n// - Adds resource hints for the configured wallet origin (dns‑prefetch, preconnect, prefetch)\n// and modulepreload for the wallet host script.\n// - Sets `window.__W3A_WALLET_SDK_BASE__` to an absolute `${walletOrigin}${sdkBasePath}/` so\n// any embedded srcdoc iframes created by the SDK load ESM bundles from the wallet origin,\n// not from the host app origin.\n//\n// Requirements\n// - `config.iframeWallet.walletOrigin` points to the wallet site (e.g. https://web3authn.org)\n// - `config.iframeWallet.sdkBasePath` (default '/sdk') is served on that wallet site\n// - `config.iframeWallet.walletServicePath` (default '/wallet-service') is reachable\n//\n// Gotchas\n// - Always resolve `${sdkBasePath}/...` with a trailing slash; otherwise `new URL('file', '/sdk')`\n// becomes `/file` instead of `/sdk/file`.\n// - For cross‑origin module/worker imports, ensure the wallet site sends CORS headers for\n// `/sdk/*` and `/sdk/workers/*` (e.g. `Access-Control-Allow-Origin: *`) and `.wasm` has\n// `Content-Type: application/wasm`.\n// - `/wallet-service` may 308 → `/wallet-service/` on Pages; both are fine.\nexport function usePreconnectWalletAssets(config: TatchiContextProviderProps['config']): void {\n // Derive stable primitives to avoid re-running the effect on object identity changes.\n const walletOrigin = config?.iframeWallet?.walletOrigin as string | undefined;\n const servicePath = config?.iframeWallet?.walletServicePath || '/wallet-service';\n const sdkBasePath = config?.iframeWallet?.sdkBasePath || '/sdk';\n const relayerUrl = config?.relayer?.url as string | undefined;\n\n React.useEffect(() => {\n try {\n if (typeof document === 'undefined') return;\n // Determine cross‑origin once per effect and expose absolute embedded base\n // for srcdoc iframes ONLY when wallet is cross‑origin.\n let isCrossOrigin = false;\n let walletOriginOrigin: string | undefined = undefined;\n let walletIsHttp = false;\n try {\n if (walletOrigin) {\n const url = new URL(walletOrigin, window.location.href);\n walletOriginOrigin = url.origin;\n walletIsHttp = url.protocol === 'http:' || url.protocol === 'https:';\n const parentOrigin = window.location.origin;\n isCrossOrigin = walletOriginOrigin !== parentOrigin;\n if (isCrossOrigin) {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const abs = new URL(withSlash, walletOriginOrigin).toString();\n setEmbeddedBase(abs);\n }\n }\n } catch {}\n const ensureLink = (rel: string, href?: string, attrs?: Record<string, string>) => {\n try {\n if (!href) return;\n const head = document.head || document.getElementsByTagName('head')[0];\n if (!head) return;\n const selector = `link[rel=\"${rel}\"][href=\"${href}\"]`;\n if (head.querySelector(selector)) return;\n const link = document.createElement('link');\n link.rel = rel;\n link.href = href;\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n try { link.setAttribute(k, v); } catch {}\n }\n }\n head.appendChild(link);\n } catch {}\n };\n\n if (walletOrigin) {\n // Resource hints only work for network origins; skip for schemes like chrome-extension://\n // (which can cause confusing console errors and does not benefit DNS/TLS preconnect).\n if (walletIsHttp && walletOriginOrigin) {\n // Reduce DNS/TLS handshake and fetch delays for the wallet origin\n ensureLink('dns-prefetch', walletOriginOrigin);\n ensureLink('preconnect', walletOriginOrigin, { crossorigin: '' });\n\n // Prefetch the service HTML document only in same‑origin dev.\n // Cross‑origin prefetch would require ACAO on the HTML, which we purposely avoid.\n if (!isCrossOrigin) {\n try {\n const serviceUrl = new URL(servicePath, walletOriginOrigin).toString();\n ensureLink('prefetch', serviceUrl, { as: 'document' });\n } catch {}\n }\n\n // Preload the wallet host script module so the iframe boots faster\n // Ensure the base URL ends with a trailing slash; otherwise new URL('file', base)\n // would replace the last path segment (\"/sdk\") and yield \"/wallet-iframe-host.js\".\n try {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const base = new URL(withSlash, walletOriginOrigin);\n const hostJs = new URL('wallet-iframe-host.js', base).toString();\n ensureLink('modulepreload', hostJs, { crossorigin: '' });\n\n // Optionally prefetch WASM binaries to accelerate first-use while avoiding preload warnings\n // Requires CORS + correct MIME (application/wasm) on the wallet origin\n try {\n const signerWasm = new URL('workers/wasm_signer_worker_bg.wasm', base).toString();\n ensureLink('prefetch', signerWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n try {\n const vrfWasm = new URL('workers/wasm_vrf_worker_bg.wasm', base).toString();\n ensureLink('prefetch', vrfWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n\n // // Preload core CSS used by confirmer to reduce first-paint FOUC\n // const tokensCss = new URL('w3a-components.css', base).toString();\n // const txTreeCss = new URL('tx-tree.css', base).toString();\n // const txConfirmerCss = new URL('tx-confirmer.css', base).toString();\n // const drawerCss = new URL('drawer.css', base).toString();\n // ensureLink('preload', tokensCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', txTreeCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', modalCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', drawerCss, { as: 'style', crossorigin: '' });\n } catch {}\n }\n }\n\n if (relayerUrl) {\n ensureLink('dns-prefetch', relayerUrl);\n ensureLink('preconnect', relayerUrl, { crossorigin: '' });\n }\n } catch {}\n }, [walletOrigin, servicePath, sdkBasePath, relayerUrl]);\n}\n\nexport default usePreconnectWalletAssets;\n"],"mappings":";;;;AA0BA,SAAgB,0BAA0B,QAAoD;CAE5F,MAAM,eAAe,QAAQ,cAAc;CAC3C,MAAM,cAAc,QAAQ,cAAc,qBAAqB;CAC/D,MAAM,cAAc,QAAQ,cAAc,eAAe;CACzD,MAAM,aAAa,QAAQ,SAAS;AAEpC,OAAM,gBAAgB;AACpB,MAAI;AACF,OAAI,OAAO,aAAa,YAAa;GAGrC,IAAI,gBAAgB;GACpB,IAAIA,qBAAyC;GAC7C,IAAI,eAAe;AACnB,OAAI;AACF,QAAI,cAAc;KAChB,MAAM,MAAM,IAAI,IAAI,cAAc,OAAO,SAAS;AAClD,0BAAqB,IAAI;AACzB,oBAAe,IAAI,aAAa,WAAW,IAAI,aAAa;KAC5D,MAAM,eAAe,OAAO,SAAS;AACrC,qBAAgB,uBAAuB;AACvC,SAAI,eAAe;MACjB,MAAM,UAAW,eAAe;MAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;MAC9D,MAAM,MAAM,IAAI,IAAI,WAAW,oBAAoB;AACnD,sBAAgB;;;WAGd;GACR,MAAM,cAAc,KAAa,MAAe,UAAmC;AACjF,QAAI;AACF,SAAI,CAAC,KAAM;KACX,MAAM,OAAO,SAAS,QAAQ,SAAS,qBAAqB,QAAQ;AACpE,SAAI,CAAC,KAAM;KACX,MAAM,WAAW,aAAa,IAAI,WAAW,KAAK;AAClD,SAAI,KAAK,cAAc,UAAW;KAClC,MAAM,OAAO,SAAS,cAAc;AACpC,UAAK,MAAM;AACX,UAAK,OAAO;AACZ,SAAI,MACF,MAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAClC,KAAI;AAAE,WAAK,aAAa,GAAG;aAAY;AAG3C,UAAK,YAAY;YACX;;AAGV,OAAI,cAGF;QAAI,gBAAgB,oBAAoB;AAEtC,gBAAW,gBAAgB;AAC3B,gBAAW,cAAc,oBAAoB,EAAE,aAAa;AAI5D,SAAI,CAAC,cACH,KAAI;MACF,MAAM,aAAa,IAAI,IAAI,aAAa,oBAAoB;AAC5D,iBAAW,YAAY,YAAY,EAAE,IAAI;aACnC;AAMV,SAAI;MACF,MAAM,UAAW,eAAe;MAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;MAC9D,MAAM,OAAO,IAAI,IAAI,WAAW;MAChC,MAAM,SAAS,IAAI,IAAI,yBAAyB,MAAM;AACtD,iBAAW,iBAAiB,QAAQ,EAAE,aAAa;AAInD,UAAI;OACF,MAAM,aAAa,IAAI,IAAI,sCAAsC,MAAM;AACvE,kBAAW,YAAY,YAAY;QAAE,IAAI;QAAS,aAAa;QAAI,MAAM;;cACnE;AACR,UAAI;OACF,MAAM,UAAU,IAAI,IAAI,mCAAmC,MAAM;AACjE,kBAAW,YAAY,SAAS;QAAE,IAAI;QAAS,aAAa;QAAI,MAAM;;cAChE;aAWF;;;AAIZ,OAAI,YAAY;AACd,eAAW,gBAAgB;AAC3B,eAAW,cAAc,YAAY,EAAE,aAAa;;UAEhD;IACP;EAAC;EAAc;EAAa;EAAa"}
1
+ {"version":3,"file":"usePreconnectWalletAssets.js","names":["walletOriginOrigin: string | undefined"],"sources":["../../../../src/react/hooks/usePreconnectWalletAssets.ts"],"sourcesContent":["import React from 'react';\nimport type { TatchiContextProviderProps } from '../types';\nimport { setEmbeddedBase } from '../../core/sdkPaths';\n\n// Internal: Add preconnect/prefetch hints for wallet service + relayer and\n// expose an absolute embedded asset base for srcdoc iframes.\n//\n// What this hook does\n// - Adds resource hints for the configured wallet origin (dns‑prefetch, preconnect, prefetch)\n// and modulepreload for the wallet host script.\n// - Sets `window.__W3A_WALLET_SDK_BASE__` to an absolute `${walletOrigin}${sdkBasePath}/` so\n// any embedded srcdoc iframes created by the SDK load ESM bundles from the wallet origin,\n// not from the host app origin.\n//\n// Requirements\n// - `config.iframeWallet.walletOrigin` points to the wallet site (e.g. https://web3authn.org)\n// - `config.iframeWallet.sdkBasePath` (default '/sdk') is served on that wallet site\n// - `config.iframeWallet.walletServicePath` (default '/wallet-service') is reachable\n//\n// Gotchas\n// - Always resolve `${sdkBasePath}/...` with a trailing slash; otherwise `new URL('file', '/sdk')`\n// becomes `/file` instead of `/sdk/file`.\n// - For cross‑origin module/worker imports, ensure the wallet site sends CORS headers for\n// `/sdk/*` and `/sdk/workers/*` (e.g. `Access-Control-Allow-Origin: *`) and `.wasm` has\n// `Content-Type: application/wasm`.\n// - `/wallet-service` may 308 → `/wallet-service/` on Pages; both are fine.\nexport function usePreconnectWalletAssets(config: TatchiContextProviderProps['config']): void {\n // Derive stable primitives to avoid re-running the effect on object identity changes.\n const walletOrigin = config?.iframeWallet?.walletOrigin as string | undefined;\n const servicePath = config?.iframeWallet?.walletServicePath || '/wallet-service';\n const sdkBasePath = config?.iframeWallet?.sdkBasePath || '/sdk';\n const relayerUrl = config?.relayer?.url as string | undefined;\n\n React.useEffect(() => {\n try {\n if (typeof document === 'undefined') return;\n // Determine cross‑origin once per effect and expose absolute embedded base\n // for srcdoc iframes ONLY when wallet is cross‑origin.\n let isCrossOrigin = false;\n let walletOriginOrigin: string | undefined = undefined;\n try {\n if (walletOrigin) {\n walletOriginOrigin = new URL(walletOrigin, window.location.href).origin;\n const parentOrigin = window.location.origin;\n isCrossOrigin = walletOriginOrigin !== parentOrigin;\n if (isCrossOrigin) {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const abs = new URL(withSlash, walletOriginOrigin).toString();\n setEmbeddedBase(abs);\n }\n }\n } catch {}\n const ensureLink = (rel: string, href?: string, attrs?: Record<string, string>) => {\n try {\n if (!href) return;\n const head = document.head || document.getElementsByTagName('head')[0];\n if (!head) return;\n const selector = `link[rel=\"${rel}\"][href=\"${href}\"]`;\n if (head.querySelector(selector)) return;\n const link = document.createElement('link');\n link.rel = rel;\n link.href = href;\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n try { link.setAttribute(k, v); } catch {}\n }\n }\n head.appendChild(link);\n } catch {}\n };\n\n if (walletOrigin) {\n // Reduce DNS/TLS handshake and fetch delays for the wallet origin\n ensureLink('dns-prefetch', walletOrigin);\n ensureLink('preconnect', walletOrigin, { crossorigin: '' });\n\n // Prefetch the service HTML document only in same‑origin dev.\n // Cross‑origin prefetch would require ACAO on the HTML, which we purposely avoid.\n if (!isCrossOrigin) {\n try {\n const serviceUrl = new URL(servicePath, walletOrigin).toString();\n ensureLink('prefetch', serviceUrl, { as: 'document' });\n } catch {}\n }\n\n // Preload the wallet host script module so the iframe boots faster\n // Ensure the base URL ends with a trailing slash; otherwise new URL('file', base)\n // would replace the last path segment (\"/sdk\") and yield \"/wallet-iframe-host.js\".\n try {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const base = new URL(withSlash, walletOrigin);\n const hostJs = new URL('wallet-iframe-host.js', base).toString();\n ensureLink('modulepreload', hostJs, { crossorigin: '' });\n\n // Optionally prefetch WASM binaries to accelerate first-use while avoiding preload warnings\n // Requires CORS + correct MIME (application/wasm) on the wallet origin\n try {\n const signerWasm = new URL('workers/wasm_signer_worker_bg.wasm', base).toString();\n ensureLink('prefetch', signerWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n try {\n const vrfWasm = new URL('workers/wasm_vrf_worker_bg.wasm', base).toString();\n ensureLink('prefetch', vrfWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n\n // // Preload core CSS used by confirmer to reduce first-paint FOUC\n // const tokensCss = new URL('w3a-components.css', base).toString();\n // const txTreeCss = new URL('tx-tree.css', base).toString();\n // const txConfirmerCss = new URL('tx-confirmer.css', base).toString();\n // const drawerCss = new URL('drawer.css', base).toString();\n // ensureLink('preload', tokensCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', txTreeCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', modalCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', drawerCss, { as: 'style', crossorigin: '' });\n } catch {}\n }\n\n if (relayerUrl) {\n ensureLink('dns-prefetch', relayerUrl);\n ensureLink('preconnect', relayerUrl, { crossorigin: '' });\n }\n } catch {}\n }, [walletOrigin, servicePath, sdkBasePath, relayerUrl]);\n}\n\nexport default usePreconnectWalletAssets;\n"],"mappings":";;;;AA0BA,SAAgB,0BAA0B,QAAoD;CAE5F,MAAM,eAAe,QAAQ,cAAc;CAC3C,MAAM,cAAc,QAAQ,cAAc,qBAAqB;CAC/D,MAAM,cAAc,QAAQ,cAAc,eAAe;CACzD,MAAM,aAAa,QAAQ,SAAS;AAEpC,OAAM,gBAAgB;AACpB,MAAI;AACF,OAAI,OAAO,aAAa,YAAa;GAGrC,IAAI,gBAAgB;GACpB,IAAIA,qBAAyC;AAC7C,OAAI;AACF,QAAI,cAAc;AAChB,0BAAqB,IAAI,IAAI,cAAc,OAAO,SAAS,MAAM;KACjE,MAAM,eAAe,OAAO,SAAS;AACrC,qBAAgB,uBAAuB;AACvC,SAAI,eAAe;MACjB,MAAM,UAAW,eAAe;MAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;MAC9D,MAAM,MAAM,IAAI,IAAI,WAAW,oBAAoB;AACnD,sBAAgB;;;WAGd;GACR,MAAM,cAAc,KAAa,MAAe,UAAmC;AACjF,QAAI;AACF,SAAI,CAAC,KAAM;KACX,MAAM,OAAO,SAAS,QAAQ,SAAS,qBAAqB,QAAQ;AACpE,SAAI,CAAC,KAAM;KACX,MAAM,WAAW,aAAa,IAAI,WAAW,KAAK;AAClD,SAAI,KAAK,cAAc,UAAW;KAClC,MAAM,OAAO,SAAS,cAAc;AACpC,UAAK,MAAM;AACX,UAAK,OAAO;AACZ,SAAI,MACF,MAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAClC,KAAI;AAAE,WAAK,aAAa,GAAG;aAAY;AAG3C,UAAK,YAAY;YACX;;AAGV,OAAI,cAAc;AAEhB,eAAW,gBAAgB;AAC3B,eAAW,cAAc,cAAc,EAAE,aAAa;AAItD,QAAI,CAAC,cACH,KAAI;KACF,MAAM,aAAa,IAAI,IAAI,aAAa,cAAc;AACtD,gBAAW,YAAY,YAAY,EAAE,IAAI;YACnC;AAMV,QAAI;KACF,MAAM,UAAW,eAAe;KAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;KAC9D,MAAM,OAAO,IAAI,IAAI,WAAW;KAChC,MAAM,SAAS,IAAI,IAAI,yBAAyB,MAAM;AACtD,gBAAW,iBAAiB,QAAQ,EAAE,aAAa;AAInD,SAAI;MACF,MAAM,aAAa,IAAI,IAAI,sCAAsC,MAAM;AACvE,iBAAW,YAAY,YAAY;OAAE,IAAI;OAAS,aAAa;OAAI,MAAM;;aACnE;AACR,SAAI;MACF,MAAM,UAAU,IAAI,IAAI,mCAAmC,MAAM;AACjE,iBAAW,YAAY,SAAS;OAAE,IAAI;OAAS,aAAa;OAAI,MAAM;;aAChE;YAWF;;AAGV,OAAI,YAAY;AACd,eAAW,gBAAgB;AAC3B,eAAW,cAAc,YAAY,EAAE,aAAa;;UAEhD;IACP;EAAC;EAAc;EAAa;EAAa"}
@@ -0,0 +1,63 @@
1
+ import { __esm } from "../../../../_virtual/rolldown_runtime.js";
2
+ import { IndexedDBManager, init_IndexedDBManager } from "../IndexedDBManager/index.js";
3
+
4
+ //#region src/core/EmailRecovery/emailRecoveryPendingStore.ts
5
+ var EmailRecoveryPendingStore;
6
+ var init_emailRecoveryPendingStore = __esm({ "src/core/EmailRecovery/emailRecoveryPendingStore.ts": (() => {
7
+ init_IndexedDBManager();
8
+ EmailRecoveryPendingStore = class {
9
+ getPendingTtlMs;
10
+ now;
11
+ constructor(options) {
12
+ this.getPendingTtlMs = options.getPendingTtlMs;
13
+ this.now = options.now ?? Date.now;
14
+ }
15
+ getPendingIndexKey(accountId) {
16
+ return `pendingEmailRecovery:${accountId}`;
17
+ }
18
+ getPendingRecordKey(accountId, nearPublicKey) {
19
+ return `${this.getPendingIndexKey(accountId)}:${nearPublicKey}`;
20
+ }
21
+ async get(accountId, nearPublicKey) {
22
+ const pendingTtlMs = this.getPendingTtlMs();
23
+ const indexKey = this.getPendingIndexKey(accountId);
24
+ const indexedNearPublicKey = await IndexedDBManager.clientDB.getAppState(indexKey);
25
+ const resolvedNearPublicKey = nearPublicKey ?? indexedNearPublicKey;
26
+ if (!resolvedNearPublicKey) return null;
27
+ const recordKey = this.getPendingRecordKey(accountId, resolvedNearPublicKey);
28
+ const record = await IndexedDBManager.clientDB.getAppState(recordKey);
29
+ const shouldClearIndex = indexedNearPublicKey === resolvedNearPublicKey;
30
+ if (!record) {
31
+ if (shouldClearIndex) await IndexedDBManager.clientDB.setAppState(indexKey, void 0).catch(() => {});
32
+ return null;
33
+ }
34
+ if (this.now() - record.createdAt > pendingTtlMs) {
35
+ await IndexedDBManager.clientDB.setAppState(recordKey, void 0).catch(() => {});
36
+ if (shouldClearIndex) await IndexedDBManager.clientDB.setAppState(indexKey, void 0).catch(() => {});
37
+ return null;
38
+ }
39
+ await this.touchIndex(accountId, record.nearPublicKey);
40
+ return record;
41
+ }
42
+ async set(record) {
43
+ const key = this.getPendingRecordKey(record.accountId, record.nearPublicKey);
44
+ await IndexedDBManager.clientDB.setAppState(key, record);
45
+ await this.touchIndex(record.accountId, record.nearPublicKey);
46
+ }
47
+ async clear(accountId, nearPublicKey) {
48
+ const indexKey = this.getPendingIndexKey(accountId);
49
+ const idx = await IndexedDBManager.clientDB.getAppState(indexKey).catch(() => void 0);
50
+ const resolvedNearPublicKey = nearPublicKey || idx || "";
51
+ if (resolvedNearPublicKey) await IndexedDBManager.clientDB.setAppState(this.getPendingRecordKey(accountId, resolvedNearPublicKey), void 0).catch(() => {});
52
+ if (!nearPublicKey || idx === nearPublicKey) await IndexedDBManager.clientDB.setAppState(indexKey, void 0).catch(() => {});
53
+ }
54
+ async touchIndex(accountId, nearPublicKey) {
55
+ await IndexedDBManager.clientDB.setAppState(this.getPendingIndexKey(accountId), nearPublicKey).catch(() => {});
56
+ }
57
+ };
58
+ }) });
59
+
60
+ //#endregion
61
+ init_emailRecoveryPendingStore();
62
+ export { EmailRecoveryPendingStore, init_emailRecoveryPendingStore };
63
+ //# sourceMappingURL=emailRecoveryPendingStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emailRecoveryPendingStore.js","names":[],"sources":["../../../../../../../src/core/EmailRecovery/emailRecoveryPendingStore.ts"],"sourcesContent":["import { IndexedDBManager } from '../IndexedDBManager';\nimport type { AccountId } from '../types/accountIds';\nimport type { PendingEmailRecovery } from '../TatchiPasskey/emailRecovery';\n\nexport interface PendingStore {\n get(accountId: AccountId, nearPublicKey?: string): Promise<PendingEmailRecovery | null>;\n set(record: PendingEmailRecovery): Promise<void>;\n clear(accountId: AccountId, nearPublicKey?: string): Promise<void>;\n touchIndex(accountId: AccountId, nearPublicKey: string): Promise<void>;\n}\n\ntype EmailRecoveryPendingStoreOptions = {\n getPendingTtlMs: () => number;\n now?: () => number;\n};\n\nexport class EmailRecoveryPendingStore implements PendingStore {\n private getPendingTtlMs: () => number;\n private now: () => number;\n\n constructor(options: EmailRecoveryPendingStoreOptions) {\n this.getPendingTtlMs = options.getPendingTtlMs;\n this.now = options.now ?? Date.now;\n }\n\n private getPendingIndexKey(accountId: AccountId): string {\n return `pendingEmailRecovery:${accountId}`;\n }\n\n private getPendingRecordKey(accountId: AccountId, nearPublicKey: string): string {\n return `${this.getPendingIndexKey(accountId)}:${nearPublicKey}`;\n }\n\n async get(accountId: AccountId, nearPublicKey?: string): Promise<PendingEmailRecovery | null> {\n const pendingTtlMs = this.getPendingTtlMs();\n const indexKey = this.getPendingIndexKey(accountId);\n const indexedNearPublicKey = await IndexedDBManager.clientDB.getAppState<string>(indexKey);\n const resolvedNearPublicKey = nearPublicKey ?? indexedNearPublicKey;\n if (!resolvedNearPublicKey) {\n return null;\n }\n\n const recordKey = this.getPendingRecordKey(accountId, resolvedNearPublicKey);\n const record = await IndexedDBManager.clientDB.getAppState<PendingEmailRecovery>(recordKey);\n const shouldClearIndex = indexedNearPublicKey === resolvedNearPublicKey;\n if (!record) {\n if (shouldClearIndex) {\n await IndexedDBManager.clientDB.setAppState(indexKey, undefined as any).catch(() => { });\n }\n return null;\n }\n\n if (this.now() - record.createdAt > pendingTtlMs) {\n await IndexedDBManager.clientDB.setAppState(recordKey, undefined as any).catch(() => { });\n if (shouldClearIndex) {\n await IndexedDBManager.clientDB.setAppState(indexKey, undefined as any).catch(() => { });\n }\n return null;\n }\n\n await this.touchIndex(accountId, record.nearPublicKey);\n return record;\n }\n\n async set(record: PendingEmailRecovery): Promise<void> {\n const key = this.getPendingRecordKey(record.accountId, record.nearPublicKey);\n await IndexedDBManager.clientDB.setAppState(key, record);\n await this.touchIndex(record.accountId, record.nearPublicKey);\n }\n\n async clear(accountId: AccountId, nearPublicKey?: string): Promise<void> {\n const indexKey = this.getPendingIndexKey(accountId);\n const idx = await IndexedDBManager.clientDB.getAppState<string>(indexKey).catch(() => undefined);\n\n const resolvedNearPublicKey = nearPublicKey || idx || '';\n if (resolvedNearPublicKey) {\n await IndexedDBManager.clientDB\n .setAppState(this.getPendingRecordKey(accountId, resolvedNearPublicKey), undefined as any)\n .catch(() => { });\n }\n\n if (!nearPublicKey || idx === nearPublicKey) {\n await IndexedDBManager.clientDB.setAppState(indexKey, undefined as any).catch(() => { });\n }\n }\n\n async touchIndex(accountId: AccountId, nearPublicKey: string): Promise<void> {\n await IndexedDBManager.clientDB.setAppState(this.getPendingIndexKey(accountId), nearPublicKey).catch(() => { });\n }\n}\n"],"mappings":";;;;;;;CAgBa,4BAAb,MAA+D;EAC7D,AAAQ;EACR,AAAQ;EAER,YAAY,SAA2C;AACrD,QAAK,kBAAkB,QAAQ;AAC/B,QAAK,MAAM,QAAQ,OAAO,KAAK;;EAGjC,AAAQ,mBAAmB,WAA8B;AACvD,UAAO,wBAAwB;;EAGjC,AAAQ,oBAAoB,WAAsB,eAA+B;AAC/E,UAAO,GAAG,KAAK,mBAAmB,WAAW,GAAG;;EAGlD,MAAM,IAAI,WAAsB,eAA8D;GAC5F,MAAM,eAAe,KAAK;GAC1B,MAAM,WAAW,KAAK,mBAAmB;GACzC,MAAM,uBAAuB,MAAM,iBAAiB,SAAS,YAAoB;GACjF,MAAM,wBAAwB,iBAAiB;AAC/C,OAAI,CAAC,sBACH,QAAO;GAGT,MAAM,YAAY,KAAK,oBAAoB,WAAW;GACtD,MAAM,SAAS,MAAM,iBAAiB,SAAS,YAAkC;GACjF,MAAM,mBAAmB,yBAAyB;AAClD,OAAI,CAAC,QAAQ;AACX,QAAI,iBACF,OAAM,iBAAiB,SAAS,YAAY,UAAU,QAAkB,YAAY;AAEtF,WAAO;;AAGT,OAAI,KAAK,QAAQ,OAAO,YAAY,cAAc;AAChD,UAAM,iBAAiB,SAAS,YAAY,WAAW,QAAkB,YAAY;AACrF,QAAI,iBACF,OAAM,iBAAiB,SAAS,YAAY,UAAU,QAAkB,YAAY;AAEtF,WAAO;;AAGT,SAAM,KAAK,WAAW,WAAW,OAAO;AACxC,UAAO;;EAGT,MAAM,IAAI,QAA6C;GACrD,MAAM,MAAM,KAAK,oBAAoB,OAAO,WAAW,OAAO;AAC9D,SAAM,iBAAiB,SAAS,YAAY,KAAK;AACjD,SAAM,KAAK,WAAW,OAAO,WAAW,OAAO;;EAGjD,MAAM,MAAM,WAAsB,eAAuC;GACvE,MAAM,WAAW,KAAK,mBAAmB;GACzC,MAAM,MAAM,MAAM,iBAAiB,SAAS,YAAoB,UAAU,YAAY;GAEtF,MAAM,wBAAwB,iBAAiB,OAAO;AACtD,OAAI,sBACF,OAAM,iBAAiB,SACpB,YAAY,KAAK,oBAAoB,WAAW,wBAAwB,QACxE,YAAY;AAGjB,OAAI,CAAC,iBAAiB,QAAQ,cAC5B,OAAM,iBAAiB,SAAS,YAAY,UAAU,QAAkB,YAAY;;EAIxF,MAAM,WAAW,WAAsB,eAAsC;AAC3E,SAAM,iBAAiB,SAAS,YAAY,KAAK,mBAAmB,YAAY,eAAe,YAAY"}
@@ -1,27 +1,9 @@
1
+ import { __esm } from "../../../../_virtual/rolldown_runtime.js";
1
2
  import { init_accountIds, toAccountId } from "../types/accountIds.js";
2
3
  import { IndexedDBManager, init_IndexedDBManager } from "../IndexedDBManager/index.js";
4
+ import { EmailRecoveryPendingStore, init_emailRecoveryPendingStore } from "./emailRecoveryPendingStore.js";
3
5
 
4
6
  //#region src/core/EmailRecovery/index.ts
5
- init_accountIds();
6
- init_IndexedDBManager();
7
- const canonicalizeEmail = (email) => {
8
- const raw = String(email || "").trim();
9
- if (!raw) return "";
10
- const withoutHeaderName = raw.replace(/^[a-z0-9-]+\s*:\s*/i, "").trim();
11
- const emailRegex = /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/;
12
- const angleMatch = withoutHeaderName.match(/<([^>]+)>/);
13
- const candidates = [angleMatch?.[1], withoutHeaderName].filter((v) => typeof v === "string" && v.length > 0);
14
- for (const candidate of candidates) {
15
- const cleaned = candidate.replace(/^mailto:\s*/i, "");
16
- const match = cleaned.match(emailRegex);
17
- if (match?.[1]) return match[1].trim().toLowerCase();
18
- }
19
- return withoutHeaderName.toLowerCase();
20
- };
21
- const bytesToHex = (bytes) => {
22
- const arr = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);
23
- return `0x${Array.from(arr).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
24
- };
25
7
  async function hashRecoveryEmails(emails, accountId) {
26
8
  const encoder = new TextEncoder();
27
9
  const salt = (accountId || "").trim().toLowerCase();
@@ -68,7 +50,32 @@ async function prepareRecoveryEmails(nearAccountId, recoveryEmails) {
68
50
  async function getLocalRecoveryEmails(nearAccountId) {
69
51
  return IndexedDBManager.getRecoveryEmails(nearAccountId);
70
52
  }
53
+ var canonicalizeEmail, bytesToHex;
54
+ var init_EmailRecovery = __esm({ "src/core/EmailRecovery/index.ts": (() => {
55
+ init_accountIds();
56
+ init_IndexedDBManager();
57
+ init_emailRecoveryPendingStore();
58
+ canonicalizeEmail = (email) => {
59
+ const raw = String(email || "").trim();
60
+ if (!raw) return "";
61
+ const withoutHeaderName = raw.replace(/^[a-z0-9-]+\s*:\s*/i, "").trim();
62
+ const emailRegex = /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/;
63
+ const angleMatch = withoutHeaderName.match(/<([^>]+)>/);
64
+ const candidates = [angleMatch?.[1], withoutHeaderName].filter((v) => typeof v === "string" && v.length > 0);
65
+ for (const candidate of candidates) {
66
+ const cleaned = candidate.replace(/^mailto:\s*/i, "");
67
+ const match = cleaned.match(emailRegex);
68
+ if (match?.[1]) return match[1].trim().toLowerCase();
69
+ }
70
+ return withoutHeaderName.toLowerCase();
71
+ };
72
+ bytesToHex = (bytes) => {
73
+ const arr = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);
74
+ return `0x${Array.from(arr).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
75
+ };
76
+ }) });
71
77
 
72
78
  //#endregion
73
- export { bytesToHex, getLocalRecoveryEmails, prepareRecoveryEmails };
79
+ init_EmailRecovery();
80
+ export { bytesToHex, getLocalRecoveryEmails, init_EmailRecovery, prepareRecoveryEmails };
74
81
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["hashed: number[][]","pairs: RecoveryEmailEntry[]"],"sources":["../../../../../../../src/core/EmailRecovery/index.ts"],"sourcesContent":["import type { AccountId } from '../types/accountIds';\nimport { toAccountId } from '../types/accountIds';\nimport { IndexedDBManager, type RecoveryEmailRecord } from '../IndexedDBManager';\n\nexport type RecoveryEmailEntry = {\n hashHex: string;\n email: string;\n};\n\nexport { type RecoveryEmailRecord };\n\nexport const canonicalizeEmail = (email: string): string => {\n const raw = String(email || '').trim();\n if (!raw) return '';\n\n // Handle cases where a full header line is passed in (e.g. \"From: ...\").\n const withoutHeaderName = raw.replace(/^[a-z0-9-]+\\s*:\\s*/i, '').trim();\n\n const emailRegex =\n /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)/;\n\n // Prefer the common \"Name <email@domain>\" format when present, but still\n // validate/extract the actual address via regex.\n const angleMatch = withoutHeaderName.match(/<([^>]+)>/);\n const candidates = [\n angleMatch?.[1],\n withoutHeaderName,\n ].filter((v): v is string => typeof v === 'string' && v.length > 0);\n\n for (const candidate of candidates) {\n const cleaned = candidate.replace(/^mailto:\\s*/i, '');\n const match = cleaned.match(emailRegex);\n if (match?.[1]) {\n return match[1].trim().toLowerCase();\n }\n }\n\n return withoutHeaderName.toLowerCase();\n};\n\nexport const bytesToHex = (bytes: number[] | Uint8Array): string => {\n const arr = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);\n return `0x${Array.from(arr)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')}`;\n};\n\nasync function hashRecoveryEmails(emails: string[], accountId: AccountId): Promise<number[][]> {\n const encoder = new TextEncoder();\n const salt = (accountId || '').trim().toLowerCase();\n const normalized = (emails || [])\n .map(e => e.trim())\n .filter(e => e.length > 0);\n\n const hashed: number[][] = [];\n\n for (const email of normalized) {\n try {\n const canonicalEmail = canonicalizeEmail(email);\n const input = `${canonicalEmail}|${salt}`;\n const data = encoder.encode(input);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const bytes = new Uint8Array(digest);\n hashed.push(Array.from(bytes));\n } catch {\n const bytes = encoder.encode(email.toLowerCase());\n hashed.push(Array.from(bytes));\n }\n }\n\n return hashed;\n}\n\n/**\n * Canonicalize and hash recovery emails for an account, and persist the mapping\n * (hashHex → canonical email) in IndexedDB on a best-effort basis.\n */\nexport async function prepareRecoveryEmails(nearAccountId: AccountId, recoveryEmails: string[]): Promise<{\n hashes: number[][];\n pairs: RecoveryEmailEntry[];\n}> {\n const accountId = toAccountId(nearAccountId);\n\n const trimmedEmails = (recoveryEmails || []).map(e => e.trim()).filter(e => e.length > 0);\n const canonicalEmails = trimmedEmails.map(canonicalizeEmail);\n const recoveryEmailHashes = await hashRecoveryEmails(recoveryEmails, accountId);\n\n const pairs: RecoveryEmailEntry[] = recoveryEmailHashes.map((hashBytes, idx) => ({\n hashHex: bytesToHex(hashBytes),\n email: canonicalEmails[idx],\n }));\n\n void (async () => {\n try {\n await IndexedDBManager.upsertRecoveryEmails(accountId, pairs);\n } catch (error) {\n console.warn('[EmailRecovery] Failed to persist local recovery emails', error);\n }\n })();\n\n return { hashes: recoveryEmailHashes, pairs };\n}\n\nexport async function getLocalRecoveryEmails(nearAccountId: AccountId): Promise<RecoveryEmailRecord[]> {\n return IndexedDBManager.getRecoveryEmails(nearAccountId);\n}\n"],"mappings":";;;;;;AAWA,MAAa,qBAAqB,UAA0B;CAC1D,MAAM,MAAM,OAAO,SAAS,IAAI;AAChC,KAAI,CAAC,IAAK,QAAO;CAGjB,MAAM,oBAAoB,IAAI,QAAQ,uBAAuB,IAAI;CAEjE,MAAM,aACJ;CAIF,MAAM,aAAa,kBAAkB,MAAM;CAC3C,MAAM,aAAa,CACjB,aAAa,IACb,mBACA,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS;AAEjE,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,UAAU,UAAU,QAAQ,gBAAgB;EAClD,MAAM,QAAQ,QAAQ,MAAM;AAC5B,MAAI,QAAQ,GACV,QAAO,MAAM,GAAG,OAAO;;AAI3B,QAAO,kBAAkB;;AAG3B,MAAa,cAAc,UAAyC;CAClE,MAAM,MAAM,iBAAiB,aAAa,QAAQ,WAAW,KAAK;AAClE,QAAO,KAAK,MAAM,KAAK,KACpB,KAAI,MAAK,EAAE,SAAS,IAAI,SAAS,GAAG,MACpC,KAAK;;AAGV,eAAe,mBAAmB,QAAkB,WAA2C;CAC7F,MAAM,UAAU,IAAI;CACpB,MAAM,QAAQ,aAAa,IAAI,OAAO;CACtC,MAAM,cAAc,UAAU,IAC3B,KAAI,MAAK,EAAE,QACX,QAAO,MAAK,EAAE,SAAS;CAE1B,MAAMA,SAAqB;AAE3B,MAAK,MAAM,SAAS,WAClB,KAAI;EACF,MAAM,iBAAiB,kBAAkB;EACzC,MAAM,QAAQ,GAAG,eAAe,GAAG;EACnC,MAAM,OAAO,QAAQ,OAAO;EAC5B,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW;EACrD,MAAM,QAAQ,IAAI,WAAW;AAC7B,SAAO,KAAK,MAAM,KAAK;SACjB;EACN,MAAM,QAAQ,QAAQ,OAAO,MAAM;AACnC,SAAO,KAAK,MAAM,KAAK;;AAI3B,QAAO;;;;;;AAOT,eAAsB,sBAAsB,eAA0B,gBAGnE;CACD,MAAM,YAAY,YAAY;CAE9B,MAAM,iBAAiB,kBAAkB,IAAI,KAAI,MAAK,EAAE,QAAQ,QAAO,MAAK,EAAE,SAAS;CACvF,MAAM,kBAAkB,cAAc,IAAI;CAC1C,MAAM,sBAAsB,MAAM,mBAAmB,gBAAgB;CAErE,MAAMC,QAA8B,oBAAoB,KAAK,WAAW,SAAS;EAC/E,SAAS,WAAW;EACpB,OAAO,gBAAgB;;AAGzB,EAAM,YAAY;AAChB,MAAI;AACF,SAAM,iBAAiB,qBAAqB,WAAW;WAChD,OAAO;AACd,WAAQ,KAAK,2DAA2D;;;AAI5E,QAAO;EAAE,QAAQ;EAAqB;;;AAGxC,eAAsB,uBAAuB,eAA0D;AACrG,QAAO,iBAAiB,kBAAkB"}
1
+ {"version":3,"file":"index.js","names":["hashed: number[][]","pairs: RecoveryEmailEntry[]"],"sources":["../../../../../../../src/core/EmailRecovery/index.ts"],"sourcesContent":["import type { AccountId } from '../types/accountIds';\nimport { toAccountId } from '../types/accountIds';\nimport { IndexedDBManager, type RecoveryEmailRecord } from '../IndexedDBManager';\nexport { EmailRecoveryPendingStore, type PendingStore } from './emailRecoveryPendingStore';\n\nexport type RecoveryEmailEntry = {\n hashHex: string;\n email: string;\n};\n\nexport { type RecoveryEmailRecord };\n\nexport const canonicalizeEmail = (email: string): string => {\n const raw = String(email || '').trim();\n if (!raw) return '';\n\n // Handle cases where a full header line is passed in (e.g. \"From: ...\").\n const withoutHeaderName = raw.replace(/^[a-z0-9-]+\\s*:\\s*/i, '').trim();\n\n const emailRegex =\n /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)/;\n\n // Prefer the common \"Name <email@domain>\" format when present, but still\n // validate/extract the actual address via regex.\n const angleMatch = withoutHeaderName.match(/<([^>]+)>/);\n const candidates = [\n angleMatch?.[1],\n withoutHeaderName,\n ].filter((v): v is string => typeof v === 'string' && v.length > 0);\n\n for (const candidate of candidates) {\n const cleaned = candidate.replace(/^mailto:\\s*/i, '');\n const match = cleaned.match(emailRegex);\n if (match?.[1]) {\n return match[1].trim().toLowerCase();\n }\n }\n\n return withoutHeaderName.toLowerCase();\n};\n\nexport const bytesToHex = (bytes: number[] | Uint8Array): string => {\n const arr = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);\n return `0x${Array.from(arr)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')}`;\n};\n\nasync function hashRecoveryEmails(emails: string[], accountId: AccountId): Promise<number[][]> {\n const encoder = new TextEncoder();\n const salt = (accountId || '').trim().toLowerCase();\n const normalized = (emails || [])\n .map(e => e.trim())\n .filter(e => e.length > 0);\n\n const hashed: number[][] = [];\n\n for (const email of normalized) {\n try {\n const canonicalEmail = canonicalizeEmail(email);\n const input = `${canonicalEmail}|${salt}`;\n const data = encoder.encode(input);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const bytes = new Uint8Array(digest);\n hashed.push(Array.from(bytes));\n } catch {\n const bytes = encoder.encode(email.toLowerCase());\n hashed.push(Array.from(bytes));\n }\n }\n\n return hashed;\n}\n\n/**\n * Canonicalize and hash recovery emails for an account, and persist the mapping\n * (hashHex → canonical email) in IndexedDB on a best-effort basis.\n */\nexport async function prepareRecoveryEmails(nearAccountId: AccountId, recoveryEmails: string[]): Promise<{\n hashes: number[][];\n pairs: RecoveryEmailEntry[];\n}> {\n const accountId = toAccountId(nearAccountId);\n\n const trimmedEmails = (recoveryEmails || []).map(e => e.trim()).filter(e => e.length > 0);\n const canonicalEmails = trimmedEmails.map(canonicalizeEmail);\n const recoveryEmailHashes = await hashRecoveryEmails(recoveryEmails, accountId);\n\n const pairs: RecoveryEmailEntry[] = recoveryEmailHashes.map((hashBytes, idx) => ({\n hashHex: bytesToHex(hashBytes),\n email: canonicalEmails[idx],\n }));\n\n void (async () => {\n try {\n await IndexedDBManager.upsertRecoveryEmails(accountId, pairs);\n } catch (error) {\n console.warn('[EmailRecovery] Failed to persist local recovery emails', error);\n }\n })();\n\n return { hashes: recoveryEmailHashes, pairs };\n}\n\nexport async function getLocalRecoveryEmails(nearAccountId: AccountId): Promise<RecoveryEmailRecord[]> {\n return IndexedDBManager.getRecoveryEmails(nearAccountId);\n}\n"],"mappings":";;;;;;AAgDA,eAAe,mBAAmB,QAAkB,WAA2C;CAC7F,MAAM,UAAU,IAAI;CACpB,MAAM,QAAQ,aAAa,IAAI,OAAO;CACtC,MAAM,cAAc,UAAU,IAC3B,KAAI,MAAK,EAAE,QACX,QAAO,MAAK,EAAE,SAAS;CAE1B,MAAMA,SAAqB;AAE3B,MAAK,MAAM,SAAS,WAClB,KAAI;EACF,MAAM,iBAAiB,kBAAkB;EACzC,MAAM,QAAQ,GAAG,eAAe,GAAG;EACnC,MAAM,OAAO,QAAQ,OAAO;EAC5B,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW;EACrD,MAAM,QAAQ,IAAI,WAAW;AAC7B,SAAO,KAAK,MAAM,KAAK;SACjB;EACN,MAAM,QAAQ,QAAQ,OAAO,MAAM;AACnC,SAAO,KAAK,MAAM,KAAK;;AAI3B,QAAO;;;;;;AAOT,eAAsB,sBAAsB,eAA0B,gBAGnE;CACD,MAAM,YAAY,YAAY;CAE9B,MAAM,iBAAiB,kBAAkB,IAAI,KAAI,MAAK,EAAE,QAAQ,QAAO,MAAK,EAAE,SAAS;CACvF,MAAM,kBAAkB,cAAc,IAAI;CAC1C,MAAM,sBAAsB,MAAM,mBAAmB,gBAAgB;CAErE,MAAMC,QAA8B,oBAAoB,KAAK,WAAW,SAAS;EAC/E,SAAS,WAAW;EACpB,OAAO,gBAAgB;;AAGzB,EAAM,YAAY;AAChB,MAAI;AACF,SAAM,iBAAiB,qBAAqB,WAAW;WAChD,OAAO;AACd,WAAQ,KAAK,2DAA2D;;;AAI5E,QAAO;EAAE,QAAQ;EAAqB;;;AAGxC,eAAsB,uBAAuB,eAA0D;AACrG,QAAO,iBAAiB,kBAAkB;;;;;;;CA7F/B,qBAAqB,UAA0B;EAC1D,MAAM,MAAM,OAAO,SAAS,IAAI;AAChC,MAAI,CAAC,IAAK,QAAO;EAGjB,MAAM,oBAAoB,IAAI,QAAQ,uBAAuB,IAAI;EAEjE,MAAM,aACJ;EAIF,MAAM,aAAa,kBAAkB,MAAM;EAC3C,MAAM,aAAa,CACjB,aAAa,IACb,mBACA,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS;AAEjE,OAAK,MAAM,aAAa,YAAY;GAClC,MAAM,UAAU,UAAU,QAAQ,gBAAgB;GAClD,MAAM,QAAQ,QAAQ,MAAM;AAC5B,OAAI,QAAQ,GACV,QAAO,MAAM,GAAG,OAAO;;AAI3B,SAAO,kBAAkB;;CAGd,cAAc,UAAyC;EAClE,MAAM,MAAM,iBAAiB,aAAa,QAAQ,WAAW,KAAK;AAClE,SAAO,KAAK,MAAM,KAAK,KACpB,KAAI,MAAK,EAAE,SAAS,IAAI,SAAS,GAAG,MACpC,KAAK"}