@seams/wallet 0.31.0 → 0.33.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 (68) hide show
  1. package/README.md +6 -6
  2. package/dist/.build-inputs.sha256 +1 -1
  3. package/dist/esm/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuFooter.js +38 -10
  4. package/dist/esm/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuSurface.js +23 -67
  5. package/dist/esm/SeamsWeb/walletIframe/host/ui/auth-menu/RecoveryOptions.js +60 -0
  6. package/dist/esm/SeamsWeb/walletIframe/host/ui/auth-menu/mountAuthMenuSurface.js +6 -0
  7. package/dist/esm/SeamsWeb/walletIframe/shared/authMenuPresentation.js +28 -0
  8. package/dist/esm/SeamsWeb/walletIframe/shared/messages.js +21 -10
  9. package/dist/esm/SeamsWeb/walletIframe/shared/walletAlternatives.js +4 -14
  10. package/dist/esm/core/ui/walletIcon.js +11 -3
  11. package/dist/esm/externalNear/controller.js +3 -2
  12. package/dist/esm/externalNear/meteor.js +1 -1
  13. package/dist/esm/externalNear/meteorRequest.js +8 -2
  14. package/dist/esm/react/components/HostedSeamsAuthMenu/shell.js +17 -1
  15. package/dist/esm/sdk/{host-DltV2Oan.js → host-BsVFOugh.js} +1 -1
  16. package/dist/esm/sdk/ownerNearOperation-BsIdSH0C.js +1 -0
  17. package/dist/esm/sdk/runtime-auth-CJCU2yJi.js +1 -0
  18. package/dist/{public/sdk/runtime-device-link-CGDZQK-D.js → esm/sdk/runtime-device-link-C0oXLSnz.js} +1 -1
  19. package/dist/esm/sdk/{runtime-ecdsa-tempo-BiJYKWK4.js → runtime-ecdsa-tempo-BC8u9NuI.js} +1 -1
  20. package/dist/esm/sdk/{runtime-email-otp-B0XCNDRb.js → runtime-email-otp-Cl4iu0z7.js} +1 -1
  21. package/dist/esm/sdk/{runtime-export-CXxv6KIx.js → runtime-export-BdhfErGJ.js} +1 -1
  22. package/dist/esm/sdk/{runtime-near-CuyS57wu.js → runtime-near-CT2ALBct.js} +1 -1
  23. package/dist/esm/sdk/{runtime-preferences-B2WBUZO7.js → runtime-preferences-fN2G9tct.js} +1 -1
  24. package/dist/esm/sdk/{runtime-recovery-KwVdSe94.js → runtime-recovery-n-TGLkwz.js} +1 -1
  25. package/dist/esm/sdk/{runtimeContext-Iy1vecX0.js → runtimeContext-DI28d8Qu.js} +1 -1
  26. package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
  27. package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
  28. package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
  29. package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
  30. package/dist/esm/sdk/wallet-service.css +2 -0
  31. package/dist/esm/sdk/wallet-ui.css +1 -1
  32. package/dist/public/headers.manifest.json +1 -1
  33. package/dist/public/sdk/{host-DltV2Oan.js → host-BsVFOugh.js} +1 -1
  34. package/dist/public/sdk/ownerNearOperation-BsIdSH0C.js +1 -0
  35. package/dist/public/sdk/runtime-auth-CJCU2yJi.js +1 -0
  36. package/dist/{esm/sdk/runtime-device-link-CGDZQK-D.js → public/sdk/runtime-device-link-C0oXLSnz.js} +1 -1
  37. package/dist/public/sdk/{runtime-ecdsa-tempo-BiJYKWK4.js → runtime-ecdsa-tempo-BC8u9NuI.js} +1 -1
  38. package/dist/public/sdk/{runtime-email-otp-B0XCNDRb.js → runtime-email-otp-Cl4iu0z7.js} +1 -1
  39. package/dist/public/sdk/{runtime-export-CXxv6KIx.js → runtime-export-BdhfErGJ.js} +1 -1
  40. package/dist/public/sdk/{runtime-near-CuyS57wu.js → runtime-near-CT2ALBct.js} +1 -1
  41. package/dist/public/sdk/{runtime-preferences-B2WBUZO7.js → runtime-preferences-fN2G9tct.js} +1 -1
  42. package/dist/public/sdk/{runtime-recovery-KwVdSe94.js → runtime-recovery-n-TGLkwz.js} +1 -1
  43. package/dist/public/sdk/{runtimeContext-Iy1vecX0.js → runtimeContext-DI28d8Qu.js} +1 -1
  44. package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
  45. package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
  46. package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
  47. package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
  48. package/dist/public/sdk/wallet-service.css +2 -0
  49. package/dist/public/sdk/wallet-ui.css +1 -1
  50. package/dist/public/wallet-assets.manifest.json +25 -25
  51. package/dist/public/wallet-service/index.html +4 -4
  52. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuFooter.d.ts +4 -0
  53. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuSurface.d.ts +3 -1
  54. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/ui/auth-menu/RecoveryOptions.d.ts +11 -0
  55. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/ui/auth-menu/mountAuthMenuSurface.d.ts +3 -0
  56. package/dist/types/wallet/src/SeamsWeb/walletIframe/shared/authMenuPresentation.d.ts +13 -0
  57. package/dist/types/wallet/src/SeamsWeb/walletIframe/shared/messages.d.ts +7 -1
  58. package/dist/types/wallet/src/core/ui/walletIcon.d.ts +1 -0
  59. package/dist/types/wallet/src/externalNear/meteorRequest.d.ts +3 -0
  60. package/dist/types/wallet/src/index.d.ts +1 -1
  61. package/dist/types/wallet/src/react/components/HostedSeamsAuthMenu/public.d.ts +1 -1
  62. package/dist/types/wallet/src/react/components/HostedSeamsAuthMenu/types.d.ts +6 -2
  63. package/dist/types/wallet/src/react/index.d.ts +1 -1
  64. package/package.json +1 -1
  65. package/dist/esm/sdk/ownerNearOperation-DCxxHcwX.js +0 -1
  66. package/dist/esm/sdk/runtime-auth-CP6P681o.js +0 -1
  67. package/dist/public/sdk/ownerNearOperation-DCxxHcwX.js +0 -1
  68. package/dist/public/sdk/runtime-auth-CP6P681o.js +0 -1
package/README.md CHANGED
@@ -1,19 +1,19 @@
1
1
  # Seams Wallet SDK
2
2
 
3
- `@seams/wallet` **0.31.0** provides browser wallet lifecycle, NEAR and EVM-family
3
+ `@seams/wallet` **0.33.0** provides browser wallet lifecycle, NEAR and EVM-family
4
4
  threshold signing, React components, and hosted wallet runtime assets.
5
5
 
6
6
  ## Install
7
7
 
8
8
  ```sh
9
- pnpm add @seams/wallet@0.31.0
9
+ pnpm add @seams/wallet@0.33.0
10
10
  ```
11
11
 
12
12
  React integrations require `react@19.1.1` and `react-dom@19.1.1`. Import the provider and UI from
13
13
  `@seams/wallet/react` and its stylesheet from `@seams/wallet/react/styles`.
14
14
  Keep the application package, wallet-origin assets, and
15
- `@seams/wallet-server@0.31.0` on the matching release. The wallet iframe protocol
16
- is `20.0.0`. The application and wallet host must use the same protocol version.
15
+ `@seams/wallet-server@0.33.0` on the matching release. The wallet iframe protocol
16
+ is `21.0.0`. The application and wallet host must use the same protocol version.
17
17
 
18
18
  ## Current API
19
19
 
@@ -48,7 +48,7 @@ the challenge and its expiry. The application receives the typed challenge handl
48
48
 
49
49
  ## Application sessions and fresh owner approval
50
50
 
51
- SDK 0.31.0 accepts a handoff from an explicitly trusted application backend.
51
+ SDK 0.33.0 accepts a handoff from an explicitly trusted application backend.
52
52
  Google and app-passkey login can use the same stable application user ID.
53
53
  Use `registration.registerOwnerWallet` for NEAR-only passkey onboarding and `near.prepareOwnerTransaction` for fresh approval of each transaction.
54
54
  These operations create no reusable signing authority.
@@ -57,7 +57,7 @@ See the [application-session guide](https://wallet.seams.sh/docs/guides/applicat
57
57
 
58
58
  ## Bring your own Google authentication
59
59
 
60
- SDK 0.31.0 can reuse an application's Google ID token to open associated wallet settings.
60
+ SDK 0.33.0 can reuse an application's Google ID token to open associated wallet settings.
61
61
  Configure the environment's Google client ID and let the owner associate their wallet once.
62
62
  Then pass the token after the application's existing Google login:
63
63
 
@@ -1 +1 @@
1
- 3936d9b6309a2cc5845549ca8b821c30b7501bd7905c1f843f21f042548b955e
1
+ 561810bf25a0d5d6712eade5eca689e24019e52460e1671199f624c75bb501d3
@@ -2,7 +2,7 @@ import { WalletText } from "../../../../../core/signingEngine/uiConfirm/ui/preac
2
2
  import { SeamsWordmark } from "../../../../../core/signingEngine/uiConfirm/ui/preact/SeamsWordmark.js";
3
3
  import { alertIcon } from "./icons.js";
4
4
  import { Component } from "preact";
5
- import { jsx, jsxs } from "preact/jsx-runtime";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "preact/jsx-runtime";
6
6
  //#region src/SeamsWeb/walletIframe/host/ui/auth-menu/AuthMenuFooter.tsx
7
7
  /** @jsxImportSource preact */
8
8
  /**
@@ -12,20 +12,17 @@ import { jsx, jsxs } from "preact/jsx-runtime";
12
12
  var AuthMenuFooter = class extends Component {
13
13
  shownNotice = "";
14
14
  render() {
15
- const { notice, onRetry } = this.props;
15
+ const { onRetry, brand, connection } = this.props;
16
+ const notice = footerNotice(connection, this.props.notice);
16
17
  if (notice) this.shownNotice = notice;
17
18
  return /* @__PURE__ */ jsxs("div", {
18
19
  class: "seams-auth-footer",
19
20
  "data-state": notice ? "notice" : "brand",
20
21
  children: [
21
- /* @__PURE__ */ jsxs("div", {
22
+ /* @__PURE__ */ jsx("div", {
22
23
  class: "seams-auth-footer-brand",
23
24
  "aria-hidden": notice ? "true" : void 0,
24
- children: [
25
- /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(WalletText, { message: "Secured by" }) }),
26
- " ",
27
- /* @__PURE__ */ jsx(SeamsWordmark, {})
28
- ]
25
+ children: renderBrand(brand, connection)
29
26
  }),
30
27
  /* @__PURE__ */ jsxs("div", {
31
28
  class: "seams-auth-footer-notice",
@@ -34,15 +31,16 @@ var AuthMenuFooter = class extends Component {
34
31
  /* @__PURE__ */ jsx("span", {
35
32
  class: "seams-auth-footer-text",
36
33
  "aria-hidden": "true",
34
+ title: this.shownNotice,
37
35
  children: /* @__PURE__ */ jsx(WalletText, { copy: this.shownNotice })
38
36
  }),
39
- /* @__PURE__ */ jsx("button", {
37
+ connection.kind === "idle" ? /* @__PURE__ */ jsx("button", {
40
38
  class: "seams-auth-footer-action",
41
39
  type: "button",
42
40
  disabled: !notice,
43
41
  onClick: onRetry,
44
42
  children: /* @__PURE__ */ jsx(WalletText, { message: "Try again" })
45
- })
43
+ }) : null
46
44
  ]
47
45
  }),
48
46
  notice ? /* @__PURE__ */ jsx("p", {
@@ -54,6 +52,36 @@ var AuthMenuFooter = class extends Component {
54
52
  });
55
53
  }
56
54
  };
55
+ function footerNotice(connection, notice) {
56
+ switch (connection.kind) {
57
+ case "pending": return null;
58
+ case "failed": return connection.message;
59
+ case "idle": return notice;
60
+ default: return assertNever(connection);
61
+ }
62
+ }
63
+ function renderBrand(brand, connection) {
64
+ if (connection.kind === "pending") return /* @__PURE__ */ jsx("span", {
65
+ role: "status",
66
+ children: /* @__PURE__ */ jsx(WalletText, { copy: "Complete the request in your wallet." })
67
+ });
68
+ switch (brand.kind) {
69
+ case "custom": return /* @__PURE__ */ jsx("img", {
70
+ class: "seams-auth-footer-logo",
71
+ src: brand.logo,
72
+ alt: brand.name
73
+ });
74
+ case "seams": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
75
+ /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(WalletText, { message: "Secured by" }) }),
76
+ " ",
77
+ /* @__PURE__ */ jsx(SeamsWordmark, {})
78
+ ] });
79
+ default: return assertNever(brand);
80
+ }
81
+ }
82
+ function assertNever(value) {
83
+ throw new Error(`Unknown footer state: ${value}`);
84
+ }
57
85
  //#endregion
58
86
  export { AuthMenuFooter };
59
87
 
@@ -8,8 +8,9 @@ import { AUTH_MENU_WAITING_PROMPTS, isAuthMenuActionReady, isAuthMenuGoogleActio
8
8
  import { AUTH_MENU_ACCOUNT_LIST_ID, AUTH_MENU_TITLE_ID, accountGroups, accountSecondaryText, authViewKey, menuNotice, modeLabel, modeSwitchCopy, otpCodeDigits, passkeyButtonLabel, recoveryAnnouncement, recoveryBackLabel, recoveryCaretAtPoint, recoveryNavigationLocked, renderDemoEmailCode, renderOtpCodeDigit, savedAccountsTriggerLabel, selectedAccountPrimaryText, selectedLoginAccount } from "./presentation.js";
9
9
  import { PadlockIcon } from "../../../../../core/signingEngine/uiConfirm/ui/preact/PadlockIcon.js";
10
10
  import { blinkMenuItem } from "../../../../../utils/menuItemBlink.js";
11
- import { accountDropdownIcon, backIcon, chevronIcon, fingerprintIcon, googleIcon, linkDeviceIcon, linkFailedIcon, mailIcon, passkeyRingIcon, passkeySuccessIcon, recoveryIcon, rerollIcon } from "./icons.js";
11
+ import { accountDropdownIcon, backIcon, fingerprintIcon, googleIcon, linkFailedIcon, mailIcon, passkeyRingIcon, passkeySuccessIcon, rerollIcon } from "./icons.js";
12
12
  import { AuthMenuFooter } from "./AuthMenuFooter.js";
13
+ import { RecoveryOptions } from "./RecoveryOptions.js";
13
14
  import { linkDeviceDotRing, linkDeviceEmailOtpPresentation } from "./linkDeviceBadge.js";
14
15
  import { Component, Fragment } from "preact";
15
16
  import { Fragment as Fragment$1, jsx, jsxs } from "preact/jsx-runtime";
@@ -559,7 +560,9 @@ var AuthMenuSurface = class extends Component {
559
560
  }),
560
561
  /* @__PURE__ */ jsx(AuthMenuFooter, {
561
562
  notice: menuNotice(viewModel),
562
- onRetry: this.onNoticeRetry
563
+ onRetry: this.onNoticeRetry,
564
+ brand: this.props.footerBrand,
565
+ connection: this.props.walletConnection
563
566
  })
564
567
  ]
565
568
  }) });
@@ -569,31 +572,24 @@ var AuthMenuSurface = class extends Component {
569
572
  if (viewModel.kind === "link_device") return this.renderLinkDevice(viewModel);
570
573
  if (viewModel.kind === "google_otp_login") return this.renderGoogleOtp(viewModel);
571
574
  if (viewModel.kind === "google_registration") return this.renderGoogleRegistration(viewModel);
572
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
573
- this.renderMenuHeader(viewModel),
574
- /* @__PURE__ */ jsxs("fieldset", {
575
- class: "seams-connection-controls",
576
- disabled: this.props.walletConnection.kind === "pending",
577
- children: [
578
- this.renderPasskeyInput(viewModel),
579
- this.renderAuthMethods(viewModel),
580
- /* @__PURE__ */ jsx(WalletAlternativesSection, {
581
- alternatives: this.props.walletAlternatives,
582
- onIntent: this.props.onIntent
583
- }),
584
- this.renderOtherOptions(),
585
- this.renderIntentSwitch(viewModel)
586
- ]
587
- }),
588
- this.props.walletConnection.kind === "pending" && /* @__PURE__ */ jsx("p", {
589
- role: "status",
590
- children: /* @__PURE__ */ jsx(WalletText, { copy: "Complete the request in your wallet." })
591
- }),
592
- this.props.walletConnection.kind === "failed" && /* @__PURE__ */ jsx("p", {
593
- role: "alert",
594
- children: this.props.walletConnection.message
595
- })
596
- ] });
575
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [this.renderMenuHeader(viewModel), /* @__PURE__ */ jsxs("fieldset", {
576
+ class: "seams-connection-controls",
577
+ disabled: this.props.walletConnection.kind === "pending",
578
+ children: [
579
+ this.renderPasskeyInput(viewModel),
580
+ this.renderAuthMethods(viewModel),
581
+ /* @__PURE__ */ jsx(WalletAlternativesSection, {
582
+ alternatives: this.props.walletAlternatives,
583
+ onIntent: this.props.onIntent
584
+ }),
585
+ /* @__PURE__ */ jsx(RecoveryOptions, {
586
+ display: this.props.recoveryOptions,
587
+ onLinkDevice: this.onLinkDeviceOpen,
588
+ onRecovery: this.onRecoveryOpen
589
+ }),
590
+ this.renderIntentSwitch(viewModel)
591
+ ]
592
+ })] });
597
593
  }
598
594
  renderMenuHeader(viewModel) {
599
595
  const eyebrow = modeLabel(viewModel.mode);
@@ -803,46 +799,6 @@ var AuthMenuSurface = class extends Component {
803
799
  ]
804
800
  }) });
805
801
  }
806
- renderOtherOptions() {
807
- return /* @__PURE__ */ jsxs("details", {
808
- class: "seams-menu-expander",
809
- children: [/* @__PURE__ */ jsxs("summary", { children: [/* @__PURE__ */ jsx(WalletText, { copy: "Recover or link wallet" }), chevronIcon()] }), /* @__PURE__ */ jsxs("div", {
810
- class: "seams-menu-options",
811
- children: [/* @__PURE__ */ jsxs("button", {
812
- class: "seams-menu-option",
813
- type: "button",
814
- onClick: this.onLinkDeviceOpen,
815
- children: [
816
- /* @__PURE__ */ jsx("span", {
817
- class: "seams-menu-option-icon",
818
- children: linkDeviceIcon()
819
- }),
820
- /* @__PURE__ */ jsxs("span", {
821
- class: "seams-menu-option-text",
822
- children: [/* @__PURE__ */ jsx(WalletText, { message: "Link this device" }), /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(WalletText, { message: "Scan a code with your other device" }) })]
823
- }),
824
- chevronIcon()
825
- ]
826
- }), /* @__PURE__ */ jsxs("button", {
827
- class: "seams-menu-option",
828
- type: "button",
829
- "data-recovery-action": true,
830
- onClick: this.onRecoveryOpen,
831
- children: [
832
- /* @__PURE__ */ jsx("span", {
833
- class: "seams-menu-option-icon",
834
- children: recoveryIcon()
835
- }),
836
- /* @__PURE__ */ jsxs("span", {
837
- class: "seams-menu-option-text",
838
- children: [/* @__PURE__ */ jsx(WalletText, { message: "Recover wallet" }), /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(WalletText, { message: "Use your recovery code" }) })]
839
- }),
840
- chevronIcon()
841
- ]
842
- })]
843
- })]
844
- });
845
- }
846
802
  renderRecovery(viewModel) {
847
803
  if (viewModel.stage === "enter_code") {
848
804
  const code = recoveryInputCharacters(viewModel.recoveryCode).slice(0, 32);
@@ -0,0 +1,60 @@
1
+ import { WalletText } from "../../../../../core/signingEngine/uiConfirm/ui/preact/WalletLocale.js";
2
+ import { chevronIcon, linkDeviceIcon, recoveryIcon } from "./icons.js";
3
+ import { jsx, jsxs } from "preact/jsx-runtime";
4
+ //#region src/SeamsWeb/walletIframe/host/ui/auth-menu/RecoveryOptions.tsx
5
+ function RecoveryOptions({ display, onLinkDevice, onRecovery }) {
6
+ if (display === "hidden") return null;
7
+ const options = /* @__PURE__ */ jsxs("div", {
8
+ class: "seams-menu-options",
9
+ children: [/* @__PURE__ */ jsxs("button", {
10
+ class: "seams-menu-option",
11
+ type: "button",
12
+ onClick: onLinkDevice,
13
+ children: [
14
+ /* @__PURE__ */ jsx("span", {
15
+ class: "seams-menu-option-icon",
16
+ children: linkDeviceIcon()
17
+ }),
18
+ /* @__PURE__ */ jsxs("span", {
19
+ class: "seams-menu-option-text",
20
+ children: [/* @__PURE__ */ jsx(WalletText, { message: "Link this device" }), /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(WalletText, { message: "Scan a code with your other device" }) })]
21
+ }),
22
+ chevronIcon()
23
+ ]
24
+ }), /* @__PURE__ */ jsxs("button", {
25
+ class: "seams-menu-option",
26
+ type: "button",
27
+ "data-recovery-action": true,
28
+ onClick: onRecovery,
29
+ children: [
30
+ /* @__PURE__ */ jsx("span", {
31
+ class: "seams-menu-option-icon",
32
+ children: recoveryIcon()
33
+ }),
34
+ /* @__PURE__ */ jsxs("span", {
35
+ class: "seams-menu-option-text",
36
+ children: [/* @__PURE__ */ jsx(WalletText, { message: "Recover wallet" }), /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(WalletText, { message: "Use your recovery code" }) })]
37
+ }),
38
+ chevronIcon()
39
+ ]
40
+ })]
41
+ });
42
+ switch (display) {
43
+ case "expanded": return /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("div", {
44
+ class: "seams-menu-options-label",
45
+ children: /* @__PURE__ */ jsx(WalletText, { copy: "Recover or link wallet" })
46
+ }), options] });
47
+ case "collapsible": return /* @__PURE__ */ jsxs("details", {
48
+ class: "seams-menu-expander",
49
+ children: [/* @__PURE__ */ jsxs("summary", { children: [/* @__PURE__ */ jsx(WalletText, { copy: "Recover or link wallet" }), chevronIcon()] }), options]
50
+ });
51
+ default: return assertNever(display);
52
+ }
53
+ }
54
+ function assertNever(value) {
55
+ throw new Error(`Unknown recovery display: ${value}`);
56
+ }
57
+ //#endregion
58
+ export { RecoveryOptions };
59
+
60
+ //# sourceMappingURL=RecoveryOptions.js.map
@@ -25,6 +25,8 @@ function authMenuStyles(document) {
25
25
  var MountedAuthMenuSurface = class {
26
26
  element;
27
27
  walletAlternatives;
28
+ recoveryOptions;
29
+ footerBrand;
28
30
  walletConnection = { kind: "idle" };
29
31
  viewModel;
30
32
  styles;
@@ -32,6 +34,8 @@ var MountedAuthMenuSurface = class {
32
34
  state;
33
35
  constructor(input) {
34
36
  this.walletAlternatives = input.walletAlternatives ?? emptyWalletAlternatives();
37
+ this.recoveryOptions = input.recoveryOptions ?? "collapsible";
38
+ this.footerBrand = input.footerBrand ?? { kind: "seams" };
35
39
  this.viewModel = input.viewModel;
36
40
  const document = input.parent.ownerDocument;
37
41
  this.styles = authMenuStyles(document);
@@ -90,6 +94,8 @@ var MountedAuthMenuSurface = class {
90
94
  element: this.element,
91
95
  viewModel,
92
96
  walletAlternatives: this.walletAlternatives,
97
+ recoveryOptions: this.recoveryOptions,
98
+ footerBrand: this.footerBrand,
93
99
  walletConnection: this.walletConnection,
94
100
  onIntent: this.state.onIntent,
95
101
  styles: this.styles
@@ -0,0 +1,28 @@
1
+ import { isPlainObject } from "../../../shared-ts/src/utils/validation.js";
2
+ import { parseWalletImageUrl } from "../../../core/ui/walletIcon.js";
3
+ //#region src/SeamsWeb/walletIframe/shared/authMenuPresentation.ts
4
+ function parseAuthMenuRecoveryOptions(value) {
5
+ if (value === void 0) return "collapsible";
6
+ switch (value) {
7
+ case "collapsible": return "collapsible";
8
+ case "expanded": return "expanded";
9
+ case "hidden": return "hidden";
10
+ default: return null;
11
+ }
12
+ }
13
+ function parseAuthMenuFooterBrand(value) {
14
+ if (value === void 0) return { kind: "seams" };
15
+ if (!isPlainObject(value)) return null;
16
+ if (value.kind === "seams" && Object.keys(value).length === 1) return { kind: "seams" };
17
+ if (value.kind !== "custom" || Object.keys(value).length !== 3 || typeof value.name !== "string" || !value.name.trim() || value.name.length > 512) return null;
18
+ const logo = parseWalletImageUrl(value.logo);
19
+ return logo ? {
20
+ kind: "custom",
21
+ logo,
22
+ name: value.name.trim()
23
+ } : null;
24
+ }
25
+ //#endregion
26
+ export { parseAuthMenuFooterBrand, parseAuthMenuRecoveryOptions };
27
+
28
+ //# sourceMappingURL=authMenuPresentation.js.map
@@ -1,6 +1,7 @@
1
1
  import { isPlainObject } from "../../../shared-ts/src/utils/validation.js";
2
2
  import { parseWalletAuthMethodId, parseWalletId } from "../../../shared-ts/src/utils/domainIds.js";
3
3
  import { parseWalletSessionHome } from "../../../shared-ts/src/device-linking/activeWalletSession.js";
4
+ import { parseAuthMenuFooterBrand, parseAuthMenuRecoveryOptions } from "./authMenuPresentation.js";
4
5
  import { walletIframeRequestIdFromBoundary } from "../../../core/types/walletIframeIdentity.js";
5
6
  import { emptyWalletAlternatives, parseWalletAlternatives } from "./walletAlternatives.js";
6
7
  //#region src/SeamsWeb/walletIframe/shared/messages.ts
@@ -211,7 +212,9 @@ function parseHostedAuthMenuOpenRequest(value) {
211
212
  "showProgress",
212
213
  "copy",
213
214
  "enabledExternalProviders",
214
- "walletAlternatives"
215
+ "walletAlternatives",
216
+ "recoveryOptions",
217
+ "footerBrand"
215
218
  ]) || !hasOnlyHostedAuthMenuCopyKeys(record.copy)) return null;
216
219
  const authMenuSessionId = hostedAuthMenuSessionIdFromBoundary(record.authMenuSessionId);
217
220
  const initialMode = parseAuthMenuMode(record.initialMode);
@@ -228,8 +231,10 @@ function parseHostedAuthMenuOpenRequest(value) {
228
231
  } : null;
229
232
  const registrationAccountInput = parseRegistrationAccountInput(record.registrationAccountInput);
230
233
  const providers = parseExternalProviders(record.enabledExternalProviders);
234
+ const recoveryOptions = parseAuthMenuRecoveryOptions(record.recoveryOptions);
235
+ const footerBrand = parseAuthMenuFooterBrand(record.footerBrand);
231
236
  const walletAlternatives = record.walletAlternatives === void 0 ? emptyWalletAlternatives() : parseWalletAlternatives(record.walletAlternatives);
232
- if (!authMenuSessionId || !initialMode || !loginTarget || !registrationAccountInput || typeof record.showRegistrationInput !== "boolean" || typeof record.showProgress !== "boolean" || !providers || !walletAlternatives || !isWireSerializable(record.copy, /* @__PURE__ */ new Set(), true)) return null;
237
+ if (!authMenuSessionId || !initialMode || !loginTarget || !registrationAccountInput || typeof record.showRegistrationInput !== "boolean" || typeof record.showProgress !== "boolean" || !providers || !walletAlternatives || !recoveryOptions || !footerBrand || !isWireSerializable(record.copy, /* @__PURE__ */ new Set(), true)) return null;
233
238
  return {
234
239
  kind: "hosted_auth_menu_open_v1",
235
240
  authMenuSessionId,
@@ -241,7 +246,9 @@ function parseHostedAuthMenuOpenRequest(value) {
241
246
  showProgress: record.showProgress,
242
247
  copy: normalizeHostedAuthMenuCopy(record.copy),
243
248
  enabledExternalProviders: providers,
244
- walletAlternatives
249
+ walletAlternatives,
250
+ recoveryOptions,
251
+ footerBrand
245
252
  };
246
253
  }
247
254
  function buildHostedAuthMenuOpenRequest(args) {
@@ -257,11 +264,13 @@ function buildHostedAuthMenuOpenRequest(args) {
257
264
  "showProgress",
258
265
  "copy",
259
266
  "enabledExternalProviders",
260
- "walletAlternatives"
267
+ "walletAlternatives",
268
+ "recoveryOptions",
269
+ "footerBrand"
261
270
  ]) || args.copy !== void 0 && !hasOnlyHostedAuthMenuCopyKeys(args.copy)) throw new Error("Hosted auth-menu open configuration contains unsupported fields");
262
271
  const parsedSessionId = hostedAuthMenuSessionIdFromBoundary(args.authMenuSessionId);
263
272
  if (!parsedSessionId) throw new Error("authMenuSessionId must be a non-empty string");
264
- const request = {
273
+ const parsed = parseHostedAuthMenuOpenRequest({
265
274
  kind: "hosted_auth_menu_open_v1",
266
275
  authMenuSessionId: parsedSessionId,
267
276
  initialMode: args.initialMode ?? "login",
@@ -272,10 +281,12 @@ function buildHostedAuthMenuOpenRequest(args) {
272
281
  showProgress: args.showProgress ?? false,
273
282
  copy: normalizeHostedAuthMenuCopy(args.copy),
274
283
  enabledExternalProviders: [...args.enabledExternalProviders ?? []],
275
- walletAlternatives: args.walletAlternatives ?? emptyWalletAlternatives()
276
- };
277
- if (!parseHostedAuthMenuOpenRequest(request)) throw new Error("Hosted auth-menu open request is invalid");
278
- return Object.freeze(request);
284
+ walletAlternatives: args.walletAlternatives ?? emptyWalletAlternatives(),
285
+ recoveryOptions: args.recoveryOptions ?? "collapsible",
286
+ footerBrand: args.footerBrand ?? { kind: "seams" }
287
+ });
288
+ if (!parsed) throw new Error("Hosted auth-menu open request is invalid");
289
+ return Object.freeze(parsed);
279
290
  }
280
291
  function parseHostedAuthMenuExternalAuthRequest(value) {
281
292
  const record = recordFromBoundary(value);
@@ -484,7 +495,7 @@ function parseHostedAuthMenuOutcome(value) {
484
495
  default: return null;
485
496
  }
486
497
  }
487
- const WALLET_PROTOCOL_VERSION = "20.0.0";
498
+ const WALLET_PROTOCOL_VERSION = "21.0.0";
488
499
  const WALLET_IFRAME_PROTOCOL_VERSION_MISMATCH = "WALLET_IFRAME_PROTOCOL_VERSION_MISMATCH";
489
500
  const HOSTED_WALLET_REDEMPTION_PAYLOAD_FIELDS = [
490
501
  "home",
@@ -1,5 +1,5 @@
1
1
  import { isPlainObject } from "../../../shared-ts/src/utils/validation.js";
2
- import { parseWalletDataIcon } from "../../../core/ui/walletIcon.js";
2
+ import { parseWalletImageUrl } from "../../../core/ui/walletIcon.js";
3
3
  import { walletIframeRequestIdFromBoundary } from "../../../core/types/walletIframeIdentity.js";
4
4
  import { hostedAuthMenuSessionIdFromBoundary } from "./messages.js";
5
5
  //#region src/SeamsWeb/walletIframe/shared/walletAlternatives.ts
@@ -17,21 +17,11 @@ function parseWalletIcon(value) {
17
17
  ok: true,
18
18
  value: null
19
19
  };
20
- const dataIcon = parseWalletDataIcon(value);
21
- if (dataIcon !== null) return {
20
+ const icon = parseWalletImageUrl(value);
21
+ return icon === null ? { ok: false } : {
22
22
  ok: true,
23
- value: dataIcon
23
+ value: icon
24
24
  };
25
- if (typeof value !== "string" || value.length > 131072) return { ok: false };
26
- try {
27
- if (new URL(value).protocol === "https:") return {
28
- ok: true,
29
- value
30
- };
31
- } catch {
32
- return { ok: false };
33
- }
34
- return { ok: false };
35
25
  }
36
26
  function parseWalletRows(value, ids) {
37
27
  if (!Array.isArray(value) || value.length > 32) return null;
@@ -1,10 +1,18 @@
1
- //#region src/core/ui/walletIcon.ts
2
- const MAX_WALLET_ICON_LENGTH = 131072;
1
+ function parseWalletImageUrl(value) {
2
+ const dataIcon = parseWalletDataIcon(value);
3
+ if (dataIcon !== null) return dataIcon;
4
+ if (typeof value !== "string" || value.length > 131072) return null;
5
+ try {
6
+ return new URL(value).protocol === "https:" ? value : null;
7
+ } catch {
8
+ return null;
9
+ }
10
+ }
3
11
  function parseWalletDataIcon(value) {
4
12
  if (typeof value !== "string" || value.length > 131072 || !/^data:image\/(?:png|webp|jpeg|svg\+xml)[;,]/i.test(value)) return null;
5
13
  return value;
6
14
  }
7
15
  //#endregion
8
- export { MAX_WALLET_ICON_LENGTH, parseWalletDataIcon };
16
+ export { parseWalletDataIcon, parseWalletImageUrl };
9
17
 
10
18
  //# sourceMappingURL=walletIcon.js.map
@@ -1,5 +1,6 @@
1
1
  import { createNearWalletProvider, nearWalletName } from "./wallets.js";
2
2
  import { connectedNear } from "./types.js";
3
+ import { MeteorTransportUnavailableError } from "./meteorRequest.js";
3
4
  import { executionStatus, parseAccounts, parseSubmission, validateTransaction } from "./boundary.js";
4
5
  import { parseSignedMessage, validateMessage } from "./message.js";
5
6
  //#region src/externalNear/controller.ts
@@ -86,10 +87,10 @@ var ExternalNearController = class {
86
87
  ok: true,
87
88
  value: connection
88
89
  };
89
- } catch {
90
+ } catch (error) {
90
91
  if (generation !== this.generation) return failure("connection_changed", "Wallet selection changed.");
91
92
  this.disconnect();
92
- return failure("unavailable", `${nearWalletName(wallet)} did not connect. Check the wallet and network, then try again.`);
93
+ return failure("unavailable", error instanceof MeteorTransportUnavailableError ? error.message : `${nearWalletName(wallet)} did not connect. Check the wallet and network, then try again.`);
93
94
  } finally {
94
95
  if (generation === this.generation) {
95
96
  this.pending = false;
@@ -3,8 +3,8 @@ import { base64Encode } from "../shared-ts/src/utils/base64.js";
3
3
  import { base58Decode } from "../shared-ts/src/utils/base58.js";
4
4
  import { isValidAccountId } from "../shared-ts/src/utils/near.js";
5
5
  import { ActionType, toActionArgsWasm } from "../shared-ts/src/near/actions.js";
6
- import { serialize } from "../node_modules/borsh/lib/esm/index.js";
7
6
  import { MeteorRequest, meteorTransportFromWindow } from "./meteorRequest.js";
7
+ import { serialize } from "../node_modules/borsh/lib/esm/index.js";
8
8
  //#region src/externalNear/meteor.ts
9
9
  const transactionSchema = { struct: {
10
10
  signerId: "string",
@@ -1,8 +1,14 @@
1
1
  import { isFunction, isPlainObject } from "../shared-ts/src/utils/validation.js";
2
2
  //#region src/externalNear/meteorRequest.ts
3
+ var MeteorTransportUnavailableError = class extends Error {
4
+ constructor() {
5
+ super("Open the Meteor extension and allow access to this site, then try again.");
6
+ this.name = "MeteorTransportUnavailableError";
7
+ }
8
+ };
3
9
  function meteorTransportFromWindow() {
4
10
  const raw = Reflect.get(window, "meteorComV2");
5
- if (!isPlainObject(raw) || !isFunction(raw.sendMessageDataAndRespond)) throw new Error("Meteor extension is not ready.");
11
+ if (!isPlainObject(raw) || !isFunction(raw.sendMessageDataAndRespond)) throw new MeteorTransportUnavailableError();
6
12
  const method = raw.sendMessageDataAndRespond;
7
13
  return { sendMessageDataAndRespond: callMeteor.bind(null, raw, method) };
8
14
  }
@@ -112,6 +118,6 @@ var MeteorRequest = class {
112
118
  function ignoreResult(_value) {}
113
119
  function ignoreError(_error) {}
114
120
  //#endregion
115
- export { MeteorRequest, meteorTransportFromWindow };
121
+ export { MeteorRequest, MeteorTransportUnavailableError, meteorTransportFromWindow };
116
122
 
117
123
  //# sourceMappingURL=meteorRequest.js.map
@@ -84,6 +84,8 @@ function hostedAuthMenuEffectConfigKey(config) {
84
84
  showRegistrationInput: config.showRegistrationInput,
85
85
  showProgress: config.showProgress,
86
86
  copy: config.copy,
87
+ recoveryOptions: config.recoveryOptions,
88
+ footerBrand: config.footerBrand,
87
89
  enabledExternalProviders: config.enabledExternalProviders,
88
90
  walletAlternatives: describeWalletAlternatives(config.walletAlternatives)
89
91
  });
@@ -94,6 +96,8 @@ function hostedAuthMenuEffectConfigKey(config) {
94
96
  showRegistrationInput: normalized.showRegistrationInput,
95
97
  showProgress: normalized.showProgress,
96
98
  copy: normalized.copy,
99
+ recoveryOptions: normalized.recoveryOptions,
100
+ footerBrand: normalized.footerBrand,
97
101
  enabledExternalProviders: normalized.enabledExternalProviders,
98
102
  walletAlternatives: normalized.walletAlternatives,
99
103
  walletControllers: walletAlternativesControllerKey(config.walletAlternatives)
@@ -112,6 +116,8 @@ var HostedAuthMenuSessionController = class {
112
116
  showRegistrationInput;
113
117
  showProgress;
114
118
  copy;
119
+ recoveryOptions;
120
+ footerBrand;
115
121
  externalAuthBroker;
116
122
  walletAlternatives;
117
123
  walletBroker;
@@ -133,6 +139,8 @@ var HostedAuthMenuSessionController = class {
133
139
  this.showRegistrationInput = args.showRegistrationInput;
134
140
  this.showProgress = args.showProgress;
135
141
  this.copy = args.copy;
142
+ this.recoveryOptions = args.recoveryOptions;
143
+ this.footerBrand = args.footerBrand;
136
144
  this.externalAuthBroker = args.externalAuthBroker;
137
145
  this.walletAlternatives = args.walletAlternatives;
138
146
  this.walletBroker = new WalletAlternativesBroker(args.seams.authMenu, args.authMenuSessionId, args.walletAlternatives);
@@ -171,6 +179,8 @@ var HostedAuthMenuSessionController = class {
171
179
  showRegistrationInput: this.showRegistrationInput,
172
180
  showProgress: this.showProgress,
173
181
  copy: this.copy,
182
+ recoveryOptions: this.recoveryOptions,
183
+ footerBrand: this.footerBrand,
174
184
  enabledExternalProviders: this.externalAuthBroker.current ? ["google"] : [],
175
185
  walletAlternatives: describeWalletAlternatives(this.walletAlternatives.current)
176
186
  });
@@ -289,7 +299,7 @@ function forwardHostedAuthMenuOutcome(terminalGateRef, onOutcomeRef, outcome) {
289
299
  if (isTerminalHostedAuthMenuSuccess(outcome) && terminalGateRef.current) terminalGateRef.current.completed = true;
290
300
  onOutcomeRef.current(outcome);
291
301
  }
292
- const HostedSeamsAuthMenu = ({ initialMode = "login", initialHeightCssPx, placeholder, registrationAccountInput = "implicit_wallet", showRegistrationInput = false, showProgress = false, copy, externalAuthBroker = null, walletAlternatives, onOutcome }) => {
302
+ const HostedSeamsAuthMenu = ({ initialMode = "login", initialHeightCssPx, placeholder, registrationAccountInput = "implicit_wallet", showRegistrationInput = false, showProgress = false, copy, recoveryOptions, footerBrand, externalAuthBroker = null, walletAlternatives, onOutcome }) => {
293
303
  const { seams, isLoggedIn } = useOptionalSeams();
294
304
  const terminalGate = terminalGateFor(seams);
295
305
  syncTerminalGate(terminalGate, isLoggedIn);
@@ -300,6 +310,8 @@ const HostedSeamsAuthMenu = ({ initialMode = "login", initialHeightCssPx, placeh
300
310
  showRegistrationInput,
301
311
  showProgress,
302
312
  copy,
313
+ recoveryOptions,
314
+ footerBrand,
303
315
  enabledExternalProviders: externalProvidersForBroker(externalAuthBroker),
304
316
  walletAlternatives
305
317
  });
@@ -317,6 +329,8 @@ const HostedSeamsAuthMenu = ({ initialMode = "login", initialHeightCssPx, placeh
317
329
  showRegistrationInput,
318
330
  showProgress,
319
331
  copy,
332
+ recoveryOptions,
333
+ footerBrand,
320
334
  enabledExternalProviders: externalProvidersForBroker(externalAuthBroker),
321
335
  walletAlternatives
322
336
  };
@@ -341,6 +355,8 @@ const HostedSeamsAuthMenu = ({ initialMode = "login", initialHeightCssPx, placeh
341
355
  showRegistrationInput: config.showRegistrationInput,
342
356
  showProgress: config.showProgress,
343
357
  copy: config.copy,
358
+ recoveryOptions: config.recoveryOptions,
359
+ footerBrand: config.footerBrand,
344
360
  externalAuthBroker: externalAuthBrokerRef,
345
361
  walletAlternatives: walletAlternativesRef,
346
362
  onOutcome: forwardedOutcomeRef