@seams/wallet 0.10.2 → 0.12.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 (176) hide show
  1. package/README.md +3 -3
  2. package/THIRD_PARTY_NOTICES.md +33 -1812
  3. package/dist/.build-inputs.sha256 +1 -1
  4. package/dist/esm/SeamsWeb/operations/recovery/walletRecoveryCodeBackup.js +100 -0
  5. package/dist/esm/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuSurface.js +236 -97
  6. package/dist/esm/core/signingEngine/uiConfirm/ui/preact/RecoveryCodeBackupSurface.js +558 -0
  7. package/dist/esm/core/signingEngine/uiConfirm/ui/preact/mountRecoveryCodeBackupSurface.js +82 -0
  8. package/dist/esm/core/types/sdkSentEvents.js +9 -0
  9. package/dist/esm/react/components/AccountMenuButton/AccountMenuButtonMock.js +189 -0
  10. package/dist/esm/react/components/AccountMenuButton/AccountMenuButtonView.js +137 -0
  11. package/dist/esm/react/components/AccountMenuButton/AccountMenuDeviceDetails.js +39 -0
  12. package/dist/esm/react/components/AccountMenuButton/AccountMenuDialog.js +39 -13
  13. package/dist/esm/react/components/AccountMenuButton/AccountMenuMockScreens.js +247 -0
  14. package/dist/esm/react/components/AccountMenuButton/AccountMenuScreen.js +41 -0
  15. package/dist/esm/react/components/AccountMenuButton/AuthenticationMethodRow.js +79 -0
  16. package/dist/esm/react/components/AccountMenuButton/AuthenticationMethodsModal.js +168 -174
  17. package/dist/esm/react/components/AccountMenuButton/AuthenticationMethodsView.js +19 -0
  18. package/dist/esm/react/components/AccountMenuButton/ExportKeysScreen.js +30 -0
  19. package/dist/esm/react/components/AccountMenuButton/LinkedDevicesModal.css +148 -87
  20. package/dist/esm/react/components/AccountMenuButton/LinkedDevicesModal.js +26 -5
  21. package/dist/esm/react/components/AccountMenuButton/MenuItem.js +28 -13
  22. package/dist/esm/react/components/AccountMenuButton/ProfileDropdown.css +73 -69
  23. package/dist/esm/react/components/AccountMenuButton/ProfileDropdown.js +56 -68
  24. package/dist/esm/react/components/AccountMenuButton/RecoveryCodeAcknowledgement.js +27 -0
  25. package/dist/esm/react/components/AccountMenuButton/RecoveryCodeActions.js +53 -0
  26. package/dist/esm/react/components/AccountMenuButton/TransactionSettingsSection.css +3 -1
  27. package/dist/esm/react/components/AccountMenuButton/TransactionSettingsSection.js +2 -8
  28. package/dist/esm/react/components/AccountMenuButton/UserAccountButton.css +1 -1
  29. package/dist/esm/react/components/AccountMenuButton/UserAccountButton.js +6 -3
  30. package/dist/esm/react/components/AccountMenuButton/WalletRegionSection.js +4 -4
  31. package/dist/esm/react/components/AccountMenuButton/Web3AuthProfileButton.css +443 -12
  32. package/dist/esm/react/components/AccountMenuButton/hooks/useProfileState.js +1 -1
  33. package/dist/esm/react/components/AccountMenuButton/icons/LayersIcon.js +8 -0
  34. package/dist/esm/react/components/AccountMenuButton/icons/LockKeyholeIcon.js +22 -0
  35. package/dist/esm/react/components/AccountMenuButton/icons/PlusIcon.js +8 -0
  36. package/dist/esm/react/components/AccountMenuButton/icons/SunIcon.js +2 -2
  37. package/dist/esm/react/components/AccountMenuButton/icons/TouchIcon.css +0 -8
  38. package/dist/esm/react/components/AccountMenuButton/index.js +135 -115
  39. package/dist/esm/react/components/QRCodeScanner.js +64 -40
  40. package/dist/esm/react/components/QRCodeScannerCamera.js +16 -0
  41. package/dist/esm/react/components/ShowQRCode.js +2 -2
  42. package/dist/esm/react/externalEvm.js +2 -2
  43. package/dist/esm/react/index.js +2 -1
  44. package/dist/esm/react/styles/styles.css +520 -91
  45. package/dist/esm/react/transactionReview/TransactionReviewHost.js +3 -3
  46. package/dist/esm/sdk/{adapters-DYPu0nK9.js → adapters-CGvNLOfZ.js} +1 -1
  47. package/dist/{public/sdk/display-DjoWrSgE.js → esm/sdk/display-DTbGoX4e.js} +1 -1
  48. package/dist/{public/sdk/exportKeypairOperation-DYCzCbqL.js → esm/sdk/exportKeypairOperation-BHXMSA3v.js} +1 -1
  49. package/dist/{public/sdk/host-D5b19B_h.js → esm/sdk/host-CHQwi-Nm.js} +1 -1
  50. package/dist/esm/sdk/{localOnly-KvZeKkH5.js → localOnly-CUVRoMy2.js} +1 -1
  51. package/dist/esm/sdk/{mountRecoveryCodeBackupSurface-BA2ttbTM.js → mountRecoveryCodeBackupSurface-D1G-iCPI.js} +2 -2
  52. package/dist/esm/sdk/{pendingWalletRecoveryCodeBackup-BkIrbd6Q.js → pendingWalletRecoveryCodeBackup-DMg5U0Fk.js} +1 -1
  53. package/dist/esm/sdk/{recovery-entrypoint-DoXswV9I.js → recovery-entrypoint-EHY_b7Z-.js} +1 -1
  54. package/dist/esm/sdk/registration-CQxxUt5s.js +1 -0
  55. package/dist/esm/sdk/{registration-BFHEYmgh.js → registration-Drtkzrlc.js} +1 -1
  56. package/dist/esm/sdk/{requireStepUpAuth-C67sluoC.js → requireStepUpAuth-FqZSU021.js} +1 -1
  57. package/dist/esm/sdk/router_ab_ed25519_yao_client_bg.wasm +0 -0
  58. package/dist/esm/sdk/runtime-auth-DtpRz88X.js +1 -0
  59. package/dist/esm/sdk/{runtime-device-link-pf-a_-3u.js → runtime-device-link-DXjabXJb.js} +1 -1
  60. package/dist/esm/sdk/{runtime-ecdsa-tempo-Ddnuti6f.js → runtime-ecdsa-tempo-DlKMIbyP.js} +1 -1
  61. package/dist/esm/sdk/{runtime-email-otp-BAG8ZC1J.js → runtime-email-otp-BBPghU2G.js} +1 -1
  62. package/dist/esm/sdk/{runtime-export-DxL99xfn.js → runtime-export-pw-xJL8o.js} +1 -1
  63. package/dist/esm/sdk/{runtime-near-BrWP4IxC.js → runtime-near-B-vYxGjl.js} +1 -1
  64. package/dist/esm/sdk/{runtime-preferences-BjVdHYL0.js → runtime-preferences-D-hY0RfC.js} +1 -1
  65. package/dist/esm/sdk/{runtime-recovery-BNd_GX5q.js → runtime-recovery-Vg1ND2nl.js} +1 -1
  66. package/dist/esm/sdk/{runtime-recovery-codes-Dn-NccpU.js → runtime-recovery-codes-rLR4Guy4.js} +1 -1
  67. package/dist/esm/sdk/sdkSentEvents-Dl8fOL50.js +1 -0
  68. package/dist/esm/sdk/shared-6bpRPbcM.js +6 -0
  69. package/dist/{public/sdk/signEvmFamily-DjD3tn8e.js → esm/sdk/signEvmFamily-M0trbeZe.js} +1 -1
  70. package/dist/esm/sdk/{signEvmFamilyWithUiConfirmForTempo-CwRFbaLM.js → signEvmFamilyWithUiConfirmForTempo-Bo25SwuV.js} +1 -1
  71. package/dist/esm/sdk/{signEvmWithUiConfirm-BHG0dwVG.js → signEvmWithUiConfirm-CFcqJRj3.js} +1 -1
  72. package/dist/{public/sdk/signNear-D0tlQXb9.js → esm/sdk/signNear-DGUQZ44s.js} +1 -1
  73. package/dist/esm/sdk/{signingFlow-Mym5j6aw.js → signingFlow-DZvV4AgG.js} +1 -1
  74. package/dist/esm/sdk/{transaction-activity-Cb2JyYKv.js → transaction-activity-xfeHKJoq.js} +1 -1
  75. package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
  76. package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
  77. package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
  78. package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
  79. package/dist/esm/sdk/{wallet-recovery-D7ywcIHw.js → wallet-recovery-LMtGiEL3.js} +1 -1
  80. package/dist/esm/sdk/wallet-ui.css +1 -1
  81. package/dist/{public/sdk/walletCustodyEcdsaContinuity-B8aO2NFb.js → esm/sdk/walletCustodyEcdsaContinuity-D-gYxv6e.js} +1 -1
  82. package/dist/{public/sdk/walletRecoveryCommit-C3EgMjo-.js → esm/sdk/walletRecoveryCommit-BYRC_2li.js} +1 -1
  83. package/dist/esm/wasm/near_signer/pkg/wasm_signer_worker_bg.wasm +0 -0
  84. package/dist/esm/wasm/router_ab_ecdsa_client/pkg/router_ab_ecdsa_client_bg.wasm +0 -0
  85. package/dist/esm/wasm/router_ab_ed25519_yao_client/pkg/router_ab_ed25519_yao_client_bg.wasm +0 -0
  86. package/dist/public/headers.manifest.json +1 -1
  87. package/dist/public/sdk/{adapters-DYPu0nK9.js → adapters-CGvNLOfZ.js} +1 -1
  88. package/dist/{esm/sdk/display-DjoWrSgE.js → public/sdk/display-DTbGoX4e.js} +1 -1
  89. package/dist/{esm/sdk/exportKeypairOperation-DYCzCbqL.js → public/sdk/exportKeypairOperation-BHXMSA3v.js} +1 -1
  90. package/dist/{esm/sdk/host-D5b19B_h.js → public/sdk/host-CHQwi-Nm.js} +1 -1
  91. package/dist/public/sdk/{localOnly-KvZeKkH5.js → localOnly-CUVRoMy2.js} +1 -1
  92. package/dist/public/sdk/{mountRecoveryCodeBackupSurface-BA2ttbTM.js → mountRecoveryCodeBackupSurface-D1G-iCPI.js} +2 -2
  93. package/dist/public/sdk/{pendingWalletRecoveryCodeBackup-BkIrbd6Q.js → pendingWalletRecoveryCodeBackup-DMg5U0Fk.js} +1 -1
  94. package/dist/public/sdk/{recovery-entrypoint-DoXswV9I.js → recovery-entrypoint-EHY_b7Z-.js} +1 -1
  95. package/dist/public/sdk/registration-CQxxUt5s.js +1 -0
  96. package/dist/public/sdk/{registration-BFHEYmgh.js → registration-Drtkzrlc.js} +1 -1
  97. package/dist/public/sdk/{requireStepUpAuth-C67sluoC.js → requireStepUpAuth-FqZSU021.js} +1 -1
  98. package/dist/public/sdk/router_ab_ed25519_yao_client_bg.wasm +0 -0
  99. package/dist/public/sdk/runtime-auth-DtpRz88X.js +1 -0
  100. package/dist/public/sdk/{runtime-device-link-pf-a_-3u.js → runtime-device-link-DXjabXJb.js} +1 -1
  101. package/dist/public/sdk/{runtime-ecdsa-tempo-Ddnuti6f.js → runtime-ecdsa-tempo-DlKMIbyP.js} +1 -1
  102. package/dist/public/sdk/{runtime-email-otp-BAG8ZC1J.js → runtime-email-otp-BBPghU2G.js} +1 -1
  103. package/dist/public/sdk/{runtime-export-DxL99xfn.js → runtime-export-pw-xJL8o.js} +1 -1
  104. package/dist/public/sdk/{runtime-near-BrWP4IxC.js → runtime-near-B-vYxGjl.js} +1 -1
  105. package/dist/public/sdk/{runtime-preferences-BjVdHYL0.js → runtime-preferences-D-hY0RfC.js} +1 -1
  106. package/dist/public/sdk/{runtime-recovery-BNd_GX5q.js → runtime-recovery-Vg1ND2nl.js} +1 -1
  107. package/dist/public/sdk/{runtime-recovery-codes-Dn-NccpU.js → runtime-recovery-codes-rLR4Guy4.js} +1 -1
  108. package/dist/public/sdk/sdkSentEvents-Dl8fOL50.js +1 -0
  109. package/dist/public/sdk/shared-6bpRPbcM.js +6 -0
  110. package/dist/{esm/sdk/signEvmFamily-DjD3tn8e.js → public/sdk/signEvmFamily-M0trbeZe.js} +1 -1
  111. package/dist/public/sdk/{signEvmFamilyWithUiConfirmForTempo-CwRFbaLM.js → signEvmFamilyWithUiConfirmForTempo-Bo25SwuV.js} +1 -1
  112. package/dist/public/sdk/{signEvmWithUiConfirm-BHG0dwVG.js → signEvmWithUiConfirm-CFcqJRj3.js} +1 -1
  113. package/dist/{esm/sdk/signNear-D0tlQXb9.js → public/sdk/signNear-DGUQZ44s.js} +1 -1
  114. package/dist/public/sdk/{signingFlow-Mym5j6aw.js → signingFlow-DZvV4AgG.js} +1 -1
  115. package/dist/public/sdk/{transaction-activity-Cb2JyYKv.js → transaction-activity-xfeHKJoq.js} +1 -1
  116. package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
  117. package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
  118. package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
  119. package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
  120. package/dist/public/sdk/{wallet-recovery-D7ywcIHw.js → wallet-recovery-LMtGiEL3.js} +1 -1
  121. package/dist/public/sdk/wallet-ui.css +1 -1
  122. package/dist/{esm/sdk/walletCustodyEcdsaContinuity-B8aO2NFb.js → public/sdk/walletCustodyEcdsaContinuity-D-gYxv6e.js} +1 -1
  123. package/dist/{esm/sdk/walletRecoveryCommit-C3EgMjo-.js → public/sdk/walletRecoveryCommit-BYRC_2li.js} +1 -1
  124. package/dist/public/sdk/workers/email_otp_runtime_bg.wasm +0 -0
  125. package/dist/public/sdk/workers/evm_crypto_bg.wasm +0 -0
  126. package/dist/public/sdk/workers/router_ab_ecdsa_client_bg.wasm +0 -0
  127. package/dist/public/sdk/workers/router_ab_ed25519_yao_client_bg.wasm +0 -0
  128. package/dist/public/sdk/workers/shamir3pass_runtime_bg.wasm +0 -0
  129. package/dist/public/sdk/workers/tempo_signer_bg.wasm +0 -0
  130. package/dist/public/sdk/workers/wallet_custody_ceremony_bg.wasm +0 -0
  131. package/dist/public/sdk/workers/wasm_signer_worker_bg.wasm +0 -0
  132. package/dist/public/wallet-assets.manifest.json +64 -64
  133. package/dist/public/wallet-service/index.html +4 -4
  134. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/auth-menu/domain.d.ts +9 -1
  135. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/auth-menu/session.d.ts +7 -3
  136. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuSurface.d.ts +8 -5
  137. package/dist/types/wallet/src/core/types/sdkSentEvents.d.ts +4 -0
  138. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuButtonMock.d.ts +17 -0
  139. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuButtonView.d.ts +17 -0
  140. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuDeviceDetails.d.ts +13 -0
  141. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuDialog.d.ts +1 -1
  142. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuMockScreens.d.ts +43 -0
  143. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuScreen.d.ts +9 -0
  144. package/dist/types/wallet/src/react/components/AccountMenuButton/AuthenticationMethodRow.d.ts +14 -0
  145. package/dist/types/wallet/src/react/components/AccountMenuButton/AuthenticationMethodsModal.d.ts +1 -1
  146. package/dist/types/wallet/src/react/components/AccountMenuButton/AuthenticationMethodsView.d.ts +8 -0
  147. package/dist/types/wallet/src/react/components/AccountMenuButton/ExportKeysScreen.d.ts +7 -0
  148. package/dist/types/wallet/src/react/components/AccountMenuButton/LinkedDevicesModal.d.ts +1 -1
  149. package/dist/types/wallet/src/react/components/AccountMenuButton/ProfileDropdown.d.ts +2 -14
  150. package/dist/types/wallet/src/react/components/AccountMenuButton/RecoveryCodeAcknowledgement.d.ts +5 -0
  151. package/dist/types/wallet/src/react/components/AccountMenuButton/RecoveryCodeActions.d.ts +5 -0
  152. package/dist/types/wallet/src/react/components/AccountMenuButton/icons/LayersIcon.d.ts +2 -0
  153. package/dist/types/wallet/src/react/components/AccountMenuButton/icons/LockKeyholeIcon.d.ts +2 -0
  154. package/dist/types/wallet/src/react/components/AccountMenuButton/icons/PlusIcon.d.ts +2 -0
  155. package/dist/types/wallet/src/react/components/AccountMenuButton/index.d.ts +2 -0
  156. package/dist/types/wallet/src/react/components/AccountMenuButton/types.d.ts +1 -14
  157. package/dist/types/wallet/src/react/components/QRCodeScanner.d.ts +1 -0
  158. package/dist/types/wallet/src/react/components/QRCodeScannerCamera.d.ts +5 -0
  159. package/dist/types/wallet/src/react/index.d.ts +2 -1
  160. package/dist/workers/email_otp_runtime_bg.wasm +0 -0
  161. package/dist/workers/evm_crypto_bg.wasm +0 -0
  162. package/dist/workers/router_ab_ecdsa_client_bg.wasm +0 -0
  163. package/dist/workers/router_ab_ed25519_yao_client_bg.wasm +0 -0
  164. package/dist/workers/shamir3pass_runtime_bg.wasm +0 -0
  165. package/dist/workers/tempo_signer_bg.wasm +0 -0
  166. package/dist/workers/wallet_custody_ceremony_bg.wasm +0 -0
  167. package/dist/workers/wasm_signer_worker_bg.wasm +0 -0
  168. package/package.json +1 -3
  169. package/dist/esm/sdk/registration-Cx_f58rb.js +0 -1
  170. package/dist/esm/sdk/runtime-auth-CKUleRYA.js +0 -1
  171. package/dist/esm/sdk/sdkSentEvents-DiQ3YVlj.js +0 -1
  172. package/dist/esm/sdk/shared-CSfgTVcf.js +0 -6
  173. package/dist/public/sdk/registration-Cx_f58rb.js +0 -1
  174. package/dist/public/sdk/runtime-auth-CKUleRYA.js +0 -1
  175. package/dist/public/sdk/sdkSentEvents-DiQ3YVlj.js +0 -1
  176. package/dist/public/sdk/shared-CSfgTVcf.js +0 -6
@@ -1 +1 @@
1
- d81ed62ded3b255b97cd863f1d3164d0b6e3a092fba5f99021a38a72eb8c2988
1
+ cac337f5d60ac07e7f5ca7219b430e7f4a2cf19050cd38956b352906687b6759
@@ -0,0 +1,100 @@
1
+ import { createWalletIframeSurfaceMeasurementReporter } from "../../walletIframe/host/surface-measurement-reporter.js";
2
+ //#region src/SeamsWeb/operations/recovery/walletRecoveryCodeBackup.ts
3
+ const CANCELLED_MESSAGE = "Recovery-code backup was cancelled before acknowledgement";
4
+ /**
5
+ * Shows the recovery-code backup dialog and resolves with the user's
6
+ * acknowledgement. This wrapper owns the promise contract: an acknowledged
7
+ * close resolves as backed-up, an unacknowledged close defers during
8
+ * registration and cancels from the account menu, and Escape always cancels.
9
+ */
10
+ async function showRecoveryCodeExperience(experience, measurementBinding = { kind: "disabled" }, options = {}) {
11
+ if (typeof document === "undefined") throw new Error("Wallet recovery-code backup requires a browser or a backup handler");
12
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
13
+ if (options.shouldCancel?.()) throw new Error(CANCELLED_MESSAGE);
14
+ const surfaceModule = await import("../../../core/signingEngine/uiConfirm/ui/preact/mountRecoveryCodeBackupSurface.js");
15
+ if (options.shouldCancel?.()) throw new Error(CANCELLED_MESSAGE);
16
+ let measurementReporter = null;
17
+ let surface = null;
18
+ let settled = false;
19
+ return await new Promise((resolve, reject) => {
20
+ const cleanup = () => {
21
+ measurementReporter?.disconnect();
22
+ measurementReporter = null;
23
+ surface?.dispose();
24
+ surface = null;
25
+ previousFocus?.focus();
26
+ };
27
+ const settle = (result) => {
28
+ if (settled) return;
29
+ settled = true;
30
+ cleanup();
31
+ if (result instanceof Error) reject(result);
32
+ else resolve(result);
33
+ };
34
+ const handleClose = (detail) => {
35
+ switch (detail.kind) {
36
+ case "dismissed":
37
+ settle(new Error(CANCELLED_MESSAGE));
38
+ return;
39
+ case "recovery_codes":
40
+ if (detail.acknowledged) {
41
+ settle({ kind: "wallet_recovery_codes_backed_up_v1" });
42
+ return;
43
+ }
44
+ if (experience.kind === "direct_backup" && experience.request.continuation === "registration_may_defer") {
45
+ settle({ kind: "wallet_recovery_code_backup_deferred_v1" });
46
+ return;
47
+ }
48
+ settle(new Error(CANCELLED_MESSAGE));
49
+ return;
50
+ }
51
+ };
52
+ try {
53
+ surface = surfaceModule.mountRecoveryCodeBackupSurface({
54
+ parent: document.body,
55
+ appearance: options.appearance,
56
+ experience,
57
+ surface: measurementBinding.kind === "wallet_iframe" ? "wallet-iframe" : "standalone",
58
+ onClose: handleClose,
59
+ onCancel: () => settle(new Error(CANCELLED_MESSAGE)),
60
+ onShown: (dialog) => {
61
+ if (settled || measurementBinding.kind !== "wallet_iframe") return;
62
+ measurementReporter = createWalletIframeSurfaceMeasurementReporter({
63
+ kind: "request_scroll_surface",
64
+ requestId: measurementBinding.requestId,
65
+ element: dialog,
66
+ postMeasurement: postRecoveryMeasurement.bind(null, dialog, measurementBinding.postMeasurement)
67
+ });
68
+ }
69
+ });
70
+ } catch (error) {
71
+ settle(error instanceof Error ? error : new Error(String(error)));
72
+ }
73
+ });
74
+ }
75
+ async function showWalletRecoveryCodeBackupUi(request, measurementBinding = { kind: "disabled" }) {
76
+ return await showRecoveryCodeExperience({
77
+ kind: "direct_backup",
78
+ request
79
+ }, measurementBinding);
80
+ }
81
+ async function showWalletRecoveryCodesUi(request, measurementBinding = { kind: "disabled" }, options = {}) {
82
+ return await showRecoveryCodeExperience({
83
+ kind: "account_menu",
84
+ ...request
85
+ }, measurementBinding, options);
86
+ }
87
+ function postRecoveryMeasurement(dialog, postMeasurement, measurement) {
88
+ if (measurement.kind !== "measured_v1") throw new Error("Recovery codes require a request surface measurement");
89
+ postMeasurement({
90
+ kind: "measured_v1",
91
+ requestId: measurement.requestId,
92
+ sequence: measurement.sequence,
93
+ widthCssPx: dialog.dataset.seamsRecoveryStage === "recovery_codes" ? 688 : 480,
94
+ heightCssPx: measurement.heightCssPx
95
+ });
96
+ }
97
+ //#endregion
98
+ export { showWalletRecoveryCodeBackupUi, showWalletRecoveryCodesUi };
99
+
100
+ //# sourceMappingURL=walletRecoveryCodeBackup.js.map
@@ -1,4 +1,6 @@
1
1
  import { isLinkedDeviceTargetEmailAddressV1 } from "../../../../../core/types/linkDevice.js";
2
+ import { EMAIL_OTP_RECOVERY_KEY_ALPHABET } from "../../../../../shared-ts/src/utils/emailOtpRecoveryKey.js";
3
+ import "../../../../../shared-ts/src/wallet-recovery/recoveryCodes.js";
2
4
  import { demoEmailOtpCodeFromDelivery } from "../../../../../core/signingEngine/session/emailOtp/challengeDelivery.js";
3
5
  import { isAuthMenuActionReady, isAuthMenuGoogleActionReady, isAuthMenuLoadingStatus, isAuthMenuReady, resolveAuthMenuLoginAccount } from "../../auth-menu/domain.js";
4
6
  import { PadlockIcon } from "../../../../../core/signingEngine/uiConfirm/ui/preact/PadlockIcon.js";
@@ -19,8 +21,40 @@ function renderDemoEmailCode(delivery) {
19
21
  }
20
22
  const AUTH_MENU_TITLE_ID = "seams-auth-menu-title";
21
23
  const AUTH_MENU_ACCOUNT_LIST_ID = "seams-auth-menu-account-list";
22
- function otpCodeDigits(code) {
23
- return code.padEnd(6, " ").slice(0, 6).split("");
24
+ function otpCodeDigits(code, length = 6) {
25
+ return code.padEnd(length, " ").slice(0, length).split("");
26
+ }
27
+ const RECOVERY_CODE_CHARACTERS = new Set(EMAIL_OTP_RECOVERY_KEY_ALPHABET);
28
+ function recoveryInputCharacters(code) {
29
+ let characters = "";
30
+ for (const character of code.toUpperCase()) {
31
+ const read = character === "O" ? "0" : character === "I" || character === "L" ? "1" : character;
32
+ if (RECOVERY_CODE_CHARACTERS.has(read)) characters += read;
33
+ }
34
+ return characters;
35
+ }
36
+ function renderRecoveryCodeGroups(code, caret) {
37
+ const groups = [];
38
+ for (let start = 0; start < 32; start += 4) {
39
+ const end = start + 4;
40
+ const slots = [];
41
+ for (let index = start; index < end; index += 1) {
42
+ const character = code[index] ?? "";
43
+ const classes = ["seams-otp-slot"];
44
+ if (character) classes.push("is-filled");
45
+ if (index === caret) classes.push("is-caret");
46
+ slots.push(/* @__PURE__ */ jsx("span", {
47
+ class: classes.join(" "),
48
+ children: character
49
+ }, index));
50
+ }
51
+ const active = caret !== null && caret >= start && caret < end;
52
+ groups.push(/* @__PURE__ */ jsx("div", {
53
+ class: `seams-recovery-code-group ${active ? "is-active" : ""}`,
54
+ children: slots
55
+ }, start));
56
+ }
57
+ return groups;
24
58
  }
25
59
  function renderOtpCodeDigit(digit) {
26
60
  return /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx("span", {
@@ -39,6 +73,10 @@ function recoveryAnnouncement(viewModel) {
39
73
  if (viewModel.stage === "sign_in_ready") return "Wallet recovered. Unlock it to continue.";
40
74
  return "";
41
75
  }
76
+ function recoveryBackLabel(viewModel) {
77
+ if (viewModel.kind !== "recovery") return "Back";
78
+ return viewModel.stage === "choose_method" ? "Back to recovery code" : "Back to unlock wallet";
79
+ }
42
80
  function recoveryNavigationLocked(viewModel) {
43
81
  return viewModel.kind === "recovery" && viewModel.stage === "finalizing";
44
82
  }
@@ -179,7 +217,10 @@ const ACCOUNT_MENU_EXIT_MS = 160;
179
217
  var AuthMenuSurface = class extends Component {
180
218
  constructor(..._args) {
181
219
  super(..._args);
182
- this.state = { accountMenu: "closed" };
220
+ this.state = {
221
+ accountMenu: "closed",
222
+ recoveryCaret: null
223
+ };
183
224
  this.accountMenuExitTimer = null;
184
225
  this.accountMenuChoice = null;
185
226
  this.previouslyFocusedElement = null;
@@ -352,13 +393,30 @@ var AuthMenuSurface = class extends Component {
352
393
  };
353
394
  this.onRecoveryCodeInput = (event) => {
354
395
  if (!(event.currentTarget instanceof HTMLInputElement)) return;
396
+ if (this.viewModel.kind !== "recovery") return;
397
+ const input = event.currentTarget;
398
+ const raw = input.value;
399
+ const caret = recoveryInputCharacters(raw.slice(0, input.selectionStart ?? raw.length)).length;
400
+ const code = recoveryInputCharacters(raw).slice(0, 32);
401
+ if (input.value !== code) {
402
+ input.value = code;
403
+ input.setSelectionRange(Math.min(caret, code.length), Math.min(caret, code.length));
404
+ }
405
+ this.syncRecoveryCaret(input);
355
406
  this.emitIntent({
356
407
  kind: "recovery_code_changed",
357
- recoveryCode: event.currentTarget.value
408
+ recoveryCode: code
358
409
  });
359
410
  };
411
+ this.onRecoveryCaretMove = (event) => {
412
+ if (event.currentTarget instanceof HTMLInputElement) this.syncRecoveryCaret(event.currentTarget);
413
+ };
414
+ this.onRecoveryCodeBlur = () => {
415
+ this.setState({ recoveryCaret: null });
416
+ };
360
417
  this.onRecoverySubmit = (event) => {
361
418
  event.preventDefault();
419
+ this.emitIntent({ kind: "recovery_code_submit" });
362
420
  };
363
421
  this.onRecoveryPasskeySelected = () => {
364
422
  this.emitIntent({ kind: "recovery_passkey_selected" });
@@ -498,6 +556,10 @@ var AuthMenuSurface = class extends Component {
498
556
  if (previous?.kind !== "recovery" || previous.stage !== "enter_code") this.props.element.querySelector("[data-recovery-code]")?.focus();
499
557
  return;
500
558
  }
559
+ if (current.stage === "choose_method") {
560
+ if (stageChanged) this.props.element.querySelector("[data-recovery-target]")?.focus();
561
+ return;
562
+ }
501
563
  const becameRecoverable = current.status.kind === "recoverable" && previous?.kind === "recovery" && previous.status.kind !== "recoverable";
502
564
  if ((stageChanged || becameRecoverable) && (current.stage === "passkey_ready" || current.stage === "finalizing" || current.stage === "sign_in_ready")) this.props.element.querySelector("[data-auth-menu-primary]")?.focus();
503
565
  }
@@ -531,6 +593,11 @@ var AuthMenuSurface = class extends Component {
531
593
  focusableElements() {
532
594
  return Array.from(this.props.element.querySelectorAll("button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], [tabindex]:not([tabindex=\"-1\"])"));
533
595
  }
596
+ syncRecoveryCaret(input) {
597
+ const caret = Math.min(input.selectionStart ?? input.value.length, 31);
598
+ const recoveryCaret = input.value.length < 32 ? caret : null;
599
+ if (recoveryCaret !== this.state.recoveryCaret) this.setState({ recoveryCaret });
600
+ }
534
601
  emitIntent(intent) {
535
602
  this.props.onIntent(intent);
536
603
  }
@@ -554,40 +621,51 @@ var AuthMenuSurface = class extends Component {
554
621
  "aria-busy": loading ? "true" : "false",
555
622
  tabIndex: -1,
556
623
  onKeyDown: this.onKeydown,
557
- children: [/* @__PURE__ */ jsxs("div", {
558
- class: "seams-content-switcher",
559
- children: [
560
- /* @__PURE__ */ jsx("button", {
561
- class: `seams-back-button ${loading || linkDevice || otpPrompt || registrationPrompt || recovery ? "is-visible" : ""}`,
562
- type: "button",
563
- "aria-label": recovery ? "Back to unlock wallet" : "Back",
564
- "data-auth-menu-close": true,
565
- disabled: recoveryNavigationLocked(viewModel),
566
- onClick: this.onBackClick,
567
- children: backIcon()
568
- }),
569
- recovery ? /* @__PURE__ */ jsx("div", {
570
- class: "sr-only",
571
- role: "status",
572
- "aria-live": "polite",
573
- "aria-atomic": "true",
574
- children: recoveryAnnouncement(viewModel)
575
- }) : null,
576
- /* @__PURE__ */ jsx("div", {
577
- class: "seams-content-area",
578
- children: /* @__PURE__ */ jsx("div", {
579
- class: "seams-content-sizer",
580
- children: loading ? this.renderWaiting(viewModel) : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx("div", {
581
- class: "seams-signin-menu",
582
- children: /* @__PURE__ */ jsx(Fragment, { children: this.renderActiveView(viewModel) }, authViewKey(viewModel))
583
- }) })
624
+ children: [
625
+ /* @__PURE__ */ jsxs("div", {
626
+ class: "seams-menu-origin",
627
+ children: [
628
+ /* @__PURE__ */ jsx(PadlockIcon, {}),
629
+ " ",
630
+ /* @__PURE__ */ jsx("span", { children: viewModel.hostname })
631
+ ]
632
+ }),
633
+ /* @__PURE__ */ jsxs("div", {
634
+ class: "seams-content-switcher",
635
+ children: [
636
+ /* @__PURE__ */ jsx("button", {
637
+ class: `seams-back-button ${loading || linkDevice || otpPrompt || registrationPrompt || recovery ? "is-visible" : ""}`,
638
+ type: "button",
639
+ "aria-label": recoveryBackLabel(viewModel),
640
+ "data-auth-menu-close": true,
641
+ disabled: recoveryNavigationLocked(viewModel),
642
+ onClick: this.onBackClick,
643
+ children: backIcon()
644
+ }),
645
+ recovery ? /* @__PURE__ */ jsx("div", {
646
+ class: "sr-only",
647
+ role: "status",
648
+ "aria-live": "polite",
649
+ "aria-atomic": "true",
650
+ children: recoveryAnnouncement(viewModel)
651
+ }) : null,
652
+ /* @__PURE__ */ jsx("div", {
653
+ class: "seams-content-area",
654
+ children: /* @__PURE__ */ jsx("div", {
655
+ class: "seams-content-sizer",
656
+ children: loading ? this.renderWaiting(viewModel) : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx("div", {
657
+ class: "seams-signin-menu",
658
+ children: /* @__PURE__ */ jsx(Fragment, { children: this.renderActiveView(viewModel) }, authViewKey(viewModel))
659
+ }) })
660
+ })
584
661
  })
585
- })
586
- ]
587
- }), /* @__PURE__ */ jsx(AuthMenuFooter, {
588
- notice: menuNotice(viewModel),
589
- onRetry: this.onNoticeRetry
590
- })]
662
+ ]
663
+ }),
664
+ /* @__PURE__ */ jsx(AuthMenuFooter, {
665
+ notice: menuNotice(viewModel),
666
+ onRetry: this.onNoticeRetry
667
+ })
668
+ ]
591
669
  }) });
592
670
  }
593
671
  renderActiveView(viewModel) {
@@ -610,14 +688,6 @@ var AuthMenuSurface = class extends Component {
610
688
  return /* @__PURE__ */ jsxs("div", {
611
689
  class: "seams-menu-header",
612
690
  children: [
613
- /* @__PURE__ */ jsxs("div", {
614
- class: "seams-menu-origin",
615
- children: [
616
- /* @__PURE__ */ jsx(PadlockIcon, {}),
617
- " ",
618
- /* @__PURE__ */ jsx("span", { children: viewModel.hostname })
619
- ]
620
- }),
621
691
  eyebrow === viewModel.heading ? null : /* @__PURE__ */ jsx("div", {
622
692
  class: "seams-menu-eyebrow",
623
693
  children: eyebrow
@@ -827,6 +897,8 @@ var AuthMenuSurface = class extends Component {
827
897
  }
828
898
  renderRecovery(viewModel) {
829
899
  if (viewModel.stage === "enter_code") {
900
+ const code = recoveryInputCharacters(viewModel.recoveryCode).slice(0, 32);
901
+ const complete = code.length === 32;
830
902
  const statusMessage = viewModel.status.kind === "recoverable" ? viewModel.status.message : "";
831
903
  const feedbackMessage = viewModel.recoveryCodeError ?? statusMessage;
832
904
  const feedbackIsError = feedbackMessage.length > 0;
@@ -845,50 +917,101 @@ var AuthMenuSurface = class extends Component {
845
917
  onSubmit: this.onRecoverySubmit,
846
918
  children: [/* @__PURE__ */ jsxs("div", {
847
919
  class: "seams-recovery-field",
848
- children: [/* @__PURE__ */ jsx("label", {
849
- class: "seams-field-label",
850
- for: "seams-recovery-code",
851
- children: "Recovery code"
852
- }), /* @__PURE__ */ jsx("input", {
853
- id: "seams-recovery-code",
854
- class: "seams-recovery-input seams-recovery-code-input",
855
- "data-recovery-code": true,
856
- name: "recoveryCode",
857
- type: "text",
858
- autocomplete: "one-time-code",
859
- autocapitalize: "characters",
860
- autocorrect: "off",
861
- spellcheck: false,
862
- "aria-invalid": viewModel.recoveryCodeError ? "true" : "false",
863
- "aria-describedby": viewModel.recoveryCodeError ? "seams-recovery-code-feedback" : "",
864
- value: viewModel.recoveryCode,
865
- onInput: this.onRecoveryCodeInput
866
- })]
867
- }), /* @__PURE__ */ jsxs("div", {
868
- class: "seams-secondary-actions",
869
- children: [/* @__PURE__ */ jsxs("button", {
870
- class: "seams-link-device-btn seams-auth-method-choice-btn",
871
- type: "button",
872
- "data-recovery-target": "passkey",
873
- onClick: this.onRecoveryPasskeySelected,
874
- children: [/* @__PURE__ */ jsx("span", {
875
- class: "seams-auth-method-choice-icon",
876
- children: fingerprintIcon()
877
- }), /* @__PURE__ */ jsx("span", { children: "Recover with Passkey" })]
878
- }), /* @__PURE__ */ jsxs("button", {
879
- class: "seams-link-device-btn seams-auth-method-choice-btn",
880
- type: "button",
881
- "data-recovery-target": "google_email_otp",
882
- onClick: this.onRecoveryGoogleSelected,
883
- children: [/* @__PURE__ */ jsx("span", {
884
- class: "seams-auth-method-choice-icon",
885
- children: googleIcon()
886
- }), /* @__PURE__ */ jsx("span", { children: "Recover with Google" })]
920
+ children: [/* @__PURE__ */ jsxs("div", {
921
+ class: "seams-recovery-field-header",
922
+ children: [/* @__PURE__ */ jsx("label", {
923
+ class: "seams-field-label",
924
+ for: "seams-recovery-code",
925
+ children: "Recovery code"
926
+ }), /* @__PURE__ */ jsxs("span", {
927
+ id: "seams-recovery-code-count",
928
+ class: "seams-recovery-code-count",
929
+ children: [
930
+ code.length,
931
+ "/",
932
+ 32
933
+ ]
934
+ })]
935
+ }), /* @__PURE__ */ jsxs("div", {
936
+ class: "seams-otp-code-field seams-recovery-code-field",
937
+ children: [/* @__PURE__ */ jsx("input", {
938
+ id: "seams-recovery-code",
939
+ class: "seams-otp-input",
940
+ "data-recovery-code": true,
941
+ name: "recoveryCode",
942
+ type: "text",
943
+ inputmode: "text",
944
+ autocomplete: "off",
945
+ autocapitalize: "characters",
946
+ autocorrect: "off",
947
+ spellcheck: false,
948
+ "aria-invalid": viewModel.recoveryCodeError ? "true" : "false",
949
+ "aria-describedby": viewModel.recoveryCodeError ? "seams-recovery-code-feedback seams-recovery-code-count" : "seams-recovery-code-count",
950
+ value: code,
951
+ onInput: this.onRecoveryCodeInput,
952
+ onFocus: this.onRecoveryCaretMove,
953
+ onKeyUp: this.onRecoveryCaretMove,
954
+ onClick: this.onRecoveryCaretMove,
955
+ onBlur: this.onRecoveryCodeBlur
956
+ }), /* @__PURE__ */ jsx("div", {
957
+ class: "seams-otp-slots seams-recovery-code-slots",
958
+ "aria-hidden": "true",
959
+ children: renderRecoveryCodeGroups(code, this.state.recoveryCaret)
960
+ })]
887
961
  })]
962
+ }), /* @__PURE__ */ jsx("button", {
963
+ class: "seams-auth-method-btn seams-auth-method-btn-primary",
964
+ type: "submit",
965
+ "data-auth-menu-primary": true,
966
+ "data-recovery-continue": true,
967
+ disabled: !complete,
968
+ children: "Continue"
888
969
  })]
889
970
  })
890
971
  ] });
891
972
  }
973
+ if (viewModel.stage === "choose_method" || viewModel.stage === "preparing") {
974
+ const busyTarget = viewModel.stage === "preparing" ? viewModel.target.kind : null;
975
+ const statusMessage = viewModel.status.kind === "recoverable" ? viewModel.status.message : viewModel.status.kind === "busy" ? viewModel.status.headline : "";
976
+ const googleEnabled = viewModel.enabledExternalProviders?.includes("google") ?? false;
977
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
978
+ this.renderHeader(viewModel),
979
+ /* @__PURE__ */ jsx("p", {
980
+ class: `seams-recovery-status ${viewModel.status.kind === "recoverable" ? "seams-recovery-error" : ""}`,
981
+ "aria-hidden": "true",
982
+ children: statusMessage
983
+ }),
984
+ /* @__PURE__ */ jsxs("div", {
985
+ class: "seams-auth-methods seams-recovery-methods",
986
+ children: [/* @__PURE__ */ jsxs("button", {
987
+ class: "seams-auth-method-btn seams-auth-method-btn-primary",
988
+ type: "button",
989
+ "data-auth-menu-primary": true,
990
+ "data-recovery-target": "passkey",
991
+ disabled: busyTarget !== null,
992
+ onClick: this.onRecoveryPasskeySelected,
993
+ children: [busyTarget === "passkey" ? /* @__PURE__ */ jsx("span", {
994
+ class: "seams-spinner",
995
+ "aria-hidden": "true"
996
+ }) : fingerprintIcon(), /* @__PURE__ */ jsx("span", { children: "Create a passkey" })]
997
+ }), googleEnabled ? /* @__PURE__ */ jsxs("button", {
998
+ class: "seams-auth-method-btn",
999
+ type: "button",
1000
+ "data-recovery-target": "google_email_otp",
1001
+ disabled: busyTarget !== null,
1002
+ onClick: this.onRecoveryGoogleSelected,
1003
+ children: [busyTarget === "google_email_otp" ? /* @__PURE__ */ jsx("span", {
1004
+ class: "seams-spinner",
1005
+ "aria-hidden": "true"
1006
+ }) : googleIcon(), /* @__PURE__ */ jsx("span", { children: "Continue with Google" })]
1007
+ }) : null]
1008
+ }),
1009
+ /* @__PURE__ */ jsx("p", {
1010
+ class: "seams-recovery-method-note",
1011
+ children: "This adds a new sign-in method to your wallet."
1012
+ })
1013
+ ] });
1014
+ }
892
1015
  if (viewModel.stage === "email_code_required") {
893
1016
  const digits = otpCodeDigits(viewModel.otpCode);
894
1017
  const canSubmit = /^\d{6}$/.test(viewModel.otpCode) && viewModel.status.kind !== "busy";
@@ -991,19 +1114,35 @@ var AuthMenuSurface = class extends Component {
991
1114
  class: "seams-waiting",
992
1115
  role: "status",
993
1116
  "aria-live": "polite",
994
- children: [/* @__PURE__ */ jsxs("div", {
995
- class: "seams-waiting-message",
996
- children: [/* @__PURE__ */ jsx("span", {
997
- class: "seams-waiting-text",
998
- children: waitingText
999
- }), viewModel.showProgress && status.detail && status.detail !== waitingText ? /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx("span", {
1000
- class: "seams-waiting-sdk-events",
1001
- children: status.detail
1002
- }) }) : null]
1003
- }), /* @__PURE__ */ jsx("div", {
1004
- "aria-label": "Loading",
1005
- class: "seams-spinner"
1006
- })]
1117
+ children: [
1118
+ status.illustration === "passkey" ? /* @__PURE__ */ jsx("span", {
1119
+ class: "seams-passkey-prompt",
1120
+ role: "img",
1121
+ "aria-label": "Passkey authentication",
1122
+ children: fingerprintIcon()
1123
+ }) : null,
1124
+ /* @__PURE__ */ jsxs("div", {
1125
+ class: "seams-waiting-message",
1126
+ children: [
1127
+ /* @__PURE__ */ jsx("span", {
1128
+ class: "seams-waiting-text",
1129
+ children: waitingText
1130
+ }),
1131
+ status.illustration === "passkey" ? /* @__PURE__ */ jsx("span", {
1132
+ class: "seams-passkey-instruction",
1133
+ children: "Complete the prompt on your device."
1134
+ }) : null,
1135
+ viewModel.showProgress && status.detail && status.detail !== waitingText ? /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx("span", {
1136
+ class: "seams-waiting-sdk-events",
1137
+ children: status.detail
1138
+ }) }) : null
1139
+ ]
1140
+ }),
1141
+ status.illustration !== "passkey" ? /* @__PURE__ */ jsx("div", {
1142
+ "aria-label": "Loading",
1143
+ class: "seams-spinner"
1144
+ }) : null
1145
+ ]
1007
1146
  }) });
1008
1147
  }
1009
1148
  renderLinkDevice(viewModel) {