@seams/wallet 0.27.0 → 0.28.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 (134) hide show
  1. package/dist/.build-inputs.sha256 +1 -1
  2. package/dist/esm/SeamsWeb/walletIframe/client/router.js +38 -0
  3. package/dist/esm/SeamsWeb/walletIframe/client/sessionCommands.js +16 -0
  4. package/dist/esm/SeamsWeb/walletIframe/host/walletMutationGuard.js +1 -0
  5. package/dist/esm/SeamsWeb/walletIframe/shared/exactSessionState.js +27 -4
  6. package/dist/esm/SeamsWeb/walletIframe/shared/messages.js +1 -1
  7. package/dist/esm/core/authMethods/plugins.js +8 -2
  8. package/dist/esm/core/ui/messages.js +5 -0
  9. package/dist/esm/react/components/AccountMenuButton/AccountMenuButtonView.js +35 -22
  10. package/dist/esm/react/components/AccountMenuButton/AccountSettingsDialog.js +157 -0
  11. package/dist/esm/react/components/AccountMenuButton/AuthenticationMethodsModal.js +13 -1
  12. package/dist/esm/react/components/AccountMenuButton/ExternalWalletSettings.js +46 -0
  13. package/dist/esm/react/components/AccountMenuButton/LinkedDevicesModal.js +14 -2
  14. package/dist/esm/react/components/AccountMenuButton/WalletSettingsLayout.js +1 -1
  15. package/dist/esm/react/components/AccountMenuButton/Web3AuthProfileButton.css +154 -5
  16. package/dist/esm/react/components/AccountMenuButton/index.js +7 -3
  17. package/dist/esm/react/context/reactLoginStateBuilders.js +20 -0
  18. package/dist/esm/react/styles/styles.css +154 -5
  19. package/dist/esm/sdk/{ConfirmationDrawer-AZruQmhP.js → ConfirmationDrawer-MJoE0AAo.js} +1 -1
  20. package/dist/{public/sdk/adapters-d9yh1bdC.js → esm/sdk/adapters-C-g_hkkZ.js} +1 -1
  21. package/dist/esm/sdk/appearance-token-vars-01eH9pgA.js +1 -0
  22. package/dist/esm/sdk/configBuilder-DpChXfDO.js +1 -0
  23. package/dist/esm/sdk/{configuration-DBEc3bsj.js → configuration-BAad7ngq.js} +1 -1
  24. package/dist/esm/sdk/{confirm-ui-nU6ymgiv.js → confirm-ui-em0vkd2m.js} +1 -1
  25. package/dist/esm/sdk/{deviceLinkApproval-CfEiotVt.js → deviceLinkApproval-x3WkiYrd.js} +1 -1
  26. package/dist/esm/sdk/{export-viewer-host-BtrKVXxu.js → export-viewer-host-BSTfHhau.js} +1 -1
  27. package/dist/{public/sdk/exportKeypairOperation-CGE9ZU1m.js → esm/sdk/exportKeypairOperation-CjST_NUK.js} +1 -1
  28. package/dist/esm/sdk/host-C51z-AxP.js +1 -0
  29. package/dist/esm/sdk/{localOnly-BATWJj78.js → localOnly-Xs89Xajm.js} +1 -1
  30. package/dist/esm/sdk/{mountExportPrivateKeySurface-CyHU8bVc.js → mountExportPrivateKeySurface-CsUEKeum.js} +1 -1
  31. package/dist/esm/sdk/{mountRecoveryCodeBackupSurface-C7aglQxf.js → mountRecoveryCodeBackupSurface-kFLo5zLk.js} +1 -1
  32. package/dist/{public/sdk/pendingWalletRecoveryCodeBackup-Cjx-X-pP.js → esm/sdk/pendingWalletRecoveryCodeBackup-B-R_U34I.js} +1 -1
  33. package/dist/esm/sdk/{registration-CNLUYN-p.js → registration-Byl4l4yZ.js} +1 -1
  34. package/dist/esm/sdk/{registration-HSwOHZOo.js → registration-C2fb9kRQ.js} +1 -1
  35. package/dist/esm/sdk/resealedEnvelopeResult-CLW00Vbw.js +1 -0
  36. package/dist/esm/sdk/runtime-auth-ufbVur2p.js +1 -0
  37. package/dist/esm/sdk/{runtime-device-link-DAsq5tGT.js → runtime-device-link-CagI2Q62.js} +1 -1
  38. package/dist/{public/sdk/runtime-ecdsa-tempo-CVh_Vwl6.js → esm/sdk/runtime-ecdsa-tempo-Rctxr0yM.js} +1 -1
  39. package/dist/{public/sdk/runtime-email-otp-BxSKK9AG.js → esm/sdk/runtime-email-otp-BQtcG-LF.js} +1 -1
  40. package/dist/esm/sdk/{runtime-export-BWnQXMzT.js → runtime-export-wTeEaqlk.js} +1 -1
  41. package/dist/esm/sdk/{runtime-near-CuzPZrDS.js → runtime-near-59yU_3ud.js} +1 -1
  42. package/dist/esm/sdk/{runtime-preferences-B-nDWlm3.js → runtime-preferences-B9qLHX8W.js} +1 -1
  43. package/dist/esm/sdk/{runtime-recovery-DpOdEJ8N.js → runtime-recovery-DNyzdMBj.js} +1 -1
  44. package/dist/esm/sdk/{runtime-recovery-codes-DeUjQsxZ.js → runtime-recovery-codes-si1fGktB.js} +1 -1
  45. package/dist/esm/sdk/runtimeContext-ByeM6Z4Z.js +6 -0
  46. package/dist/{public/sdk/sessionObservationRevision-JOvVF4Hf.js → esm/sdk/sessionObservationRevision-ihBwjS3y.js} +1 -1
  47. package/dist/esm/sdk/tx-confirm-ui.js +8 -0
  48. package/dist/esm/sdk/voiceid-host.js +1 -1
  49. package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
  50. package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
  51. package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
  52. package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
  53. package/dist/esm/sdk/{walletRecoveryAdminProof-CvSYbyg5.js → walletRecoveryAdminProof-B4Ic07jY.js} +1 -1
  54. package/dist/esm/shared-ts/src/auth/externalAuth.js +53 -0
  55. package/dist/esm/voiceid-host.js +1 -1
  56. package/dist/public/headers.manifest.json +1 -1
  57. package/dist/public/sdk/{ConfirmationDrawer-AZruQmhP.js → ConfirmationDrawer-MJoE0AAo.js} +1 -1
  58. package/dist/{esm/sdk/adapters-d9yh1bdC.js → public/sdk/adapters-C-g_hkkZ.js} +1 -1
  59. package/dist/public/sdk/appearance-token-vars-01eH9pgA.js +1 -0
  60. package/dist/public/sdk/configBuilder-DpChXfDO.js +1 -0
  61. package/dist/public/sdk/{configuration-DBEc3bsj.js → configuration-BAad7ngq.js} +1 -1
  62. package/dist/public/sdk/{confirm-ui-nU6ymgiv.js → confirm-ui-em0vkd2m.js} +1 -1
  63. package/dist/public/sdk/{deviceLinkApproval-CfEiotVt.js → deviceLinkApproval-x3WkiYrd.js} +1 -1
  64. package/dist/public/sdk/{export-viewer-host-BtrKVXxu.js → export-viewer-host-BSTfHhau.js} +1 -1
  65. package/dist/{esm/sdk/exportKeypairOperation-CGE9ZU1m.js → public/sdk/exportKeypairOperation-CjST_NUK.js} +1 -1
  66. package/dist/public/sdk/host-C51z-AxP.js +1 -0
  67. package/dist/public/sdk/{localOnly-BATWJj78.js → localOnly-Xs89Xajm.js} +1 -1
  68. package/dist/public/sdk/{mountExportPrivateKeySurface-CyHU8bVc.js → mountExportPrivateKeySurface-CsUEKeum.js} +1 -1
  69. package/dist/public/sdk/{mountRecoveryCodeBackupSurface-C7aglQxf.js → mountRecoveryCodeBackupSurface-kFLo5zLk.js} +1 -1
  70. package/dist/{esm/sdk/pendingWalletRecoveryCodeBackup-Cjx-X-pP.js → public/sdk/pendingWalletRecoveryCodeBackup-B-R_U34I.js} +1 -1
  71. package/dist/public/sdk/{registration-CNLUYN-p.js → registration-Byl4l4yZ.js} +1 -1
  72. package/dist/public/sdk/{registration-HSwOHZOo.js → registration-C2fb9kRQ.js} +1 -1
  73. package/dist/public/sdk/resealedEnvelopeResult-CLW00Vbw.js +1 -0
  74. package/dist/public/sdk/runtime-auth-ufbVur2p.js +1 -0
  75. package/dist/public/sdk/{runtime-device-link-DAsq5tGT.js → runtime-device-link-CagI2Q62.js} +1 -1
  76. package/dist/{esm/sdk/runtime-ecdsa-tempo-CVh_Vwl6.js → public/sdk/runtime-ecdsa-tempo-Rctxr0yM.js} +1 -1
  77. package/dist/{esm/sdk/runtime-email-otp-BxSKK9AG.js → public/sdk/runtime-email-otp-BQtcG-LF.js} +1 -1
  78. package/dist/public/sdk/{runtime-export-BWnQXMzT.js → runtime-export-wTeEaqlk.js} +1 -1
  79. package/dist/public/sdk/{runtime-near-CuzPZrDS.js → runtime-near-59yU_3ud.js} +1 -1
  80. package/dist/public/sdk/{runtime-preferences-B-nDWlm3.js → runtime-preferences-B9qLHX8W.js} +1 -1
  81. package/dist/public/sdk/{runtime-recovery-DpOdEJ8N.js → runtime-recovery-DNyzdMBj.js} +1 -1
  82. package/dist/public/sdk/{runtime-recovery-codes-DeUjQsxZ.js → runtime-recovery-codes-si1fGktB.js} +1 -1
  83. package/dist/public/sdk/runtimeContext-ByeM6Z4Z.js +6 -0
  84. package/dist/{esm/sdk/sessionObservationRevision-JOvVF4Hf.js → public/sdk/sessionObservationRevision-ihBwjS3y.js} +1 -1
  85. package/dist/public/sdk/tx-confirm-ui.js +8 -0
  86. package/dist/public/sdk/voiceid-host.js +1 -1
  87. package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
  88. package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
  89. package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
  90. package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
  91. package/dist/public/sdk/{walletRecoveryAdminProof-CvSYbyg5.js → walletRecoveryAdminProof-B4Ic07jY.js} +1 -1
  92. package/dist/public/wallet-assets.manifest.json +61 -61
  93. package/dist/public/wallet-service/index.html +4 -4
  94. package/dist/types/shared-ts/src/auth/externalAuth.d.ts +84 -0
  95. package/dist/types/wallet/src/SeamsWeb/operations/devices/walletHostOwnerAuthority.d.ts +2 -1
  96. package/dist/types/wallet/src/SeamsWeb/publicApi/auth.d.ts +1 -1
  97. package/dist/types/wallet/src/SeamsWeb/publicApi/types.d.ts +11 -0
  98. package/dist/types/wallet/src/SeamsWeb/walletIframe/client/router.d.ts +4 -0
  99. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/WalletHostRuntime.d.ts +4 -2
  100. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/createSessionCommands.d.ts +5 -2
  101. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/externalAuth.d.ts +29 -0
  102. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/requestRouter.d.ts +1 -1
  103. package/dist/types/wallet/src/SeamsWeb/walletIframe/host/sessionObserver.d.ts +1 -0
  104. package/dist/types/wallet/src/SeamsWeb/walletIframe/shared/messages.d.ts +3 -3
  105. package/dist/types/wallet/src/core/authMethods/plugins.d.ts +2 -0
  106. package/dist/types/wallet/src/core/types/seams.d.ts +14 -6
  107. package/dist/types/wallet/src/core/ui/messages.d.ts +1 -1
  108. package/dist/types/wallet/src/index.d.ts +1 -0
  109. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuButtonView.d.ts +2 -1
  110. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountSettingsDialog.d.ts +10 -0
  111. package/dist/types/wallet/src/react/components/AccountMenuButton/AuthenticationMethodsModal.d.ts +1 -2
  112. package/dist/types/wallet/src/react/components/AccountMenuButton/ExternalWalletSettings.d.ts +10 -0
  113. package/dist/types/wallet/src/react/components/AccountMenuButton/LinkedDevicesModal.d.ts +1 -2
  114. package/dist/types/wallet/src/react/components/AccountMenuButton/WalletSettingsLayout.d.ts +1 -0
  115. package/dist/types/wallet/src/react/components/AccountMenuButton/hooks/useProfileState.d.ts +2 -2
  116. package/dist/types/wallet/src/react/components/AccountMenuButton/types.d.ts +4 -3
  117. package/dist/types/wallet/src/react/context/reactLoginStateBuilders.d.ts +1 -1
  118. package/dist/types/wallet/src/react/types.d.ts +13 -3
  119. package/dist/types/wallet/src/voiceid-host.d.ts +2 -2
  120. package/package.json +1 -1
  121. package/dist/esm/react/components/AccountMenuButton/AccountMenuModal.js +0 -66
  122. package/dist/esm/sdk/appearance-token-vars-BJydfWT_.js +0 -1
  123. package/dist/esm/sdk/configBuilder-CSwJrmcR.js +0 -1
  124. package/dist/esm/sdk/host-DayrOrgm.js +0 -1
  125. package/dist/esm/sdk/resealedEnvelopeResult-B1p5UkYg.js +0 -1
  126. package/dist/esm/sdk/runtime-auth-BCoj7_-G.js +0 -1
  127. package/dist/esm/sdk/runtimeContext-5JcewRo3.js +0 -6
  128. package/dist/public/sdk/appearance-token-vars-BJydfWT_.js +0 -1
  129. package/dist/public/sdk/configBuilder-CSwJrmcR.js +0 -1
  130. package/dist/public/sdk/host-DayrOrgm.js +0 -1
  131. package/dist/public/sdk/resealedEnvelopeResult-B1p5UkYg.js +0 -1
  132. package/dist/public/sdk/runtime-auth-BCoj7_-G.js +0 -1
  133. package/dist/public/sdk/runtimeContext-5JcewRo3.js +0 -6
  134. package/dist/types/wallet/src/react/components/AccountMenuButton/AccountMenuModal.d.ts +0 -9
@@ -1 +1 @@
1
- 454b5591bcd47936d9aea9092966bd446c1e755578e6e1accdd9831099483a70
1
+ ea177740b9a568b4deea722dc18528d4cbfd4098970381660360b3bd1003291b
@@ -1903,6 +1903,44 @@ var WalletIframeRouter = class {
1903
1903
  }
1904
1904
  }, { timeout: "interactive" })).result;
1905
1905
  }
1906
+ async authenticate(input) {
1907
+ return (await this.post({
1908
+ type: "PM_EXTERNAL_AUTH",
1909
+ payload: {
1910
+ action: "authenticate",
1911
+ input
1912
+ }
1913
+ })).result;
1914
+ }
1915
+ async prepareExternalAuth(walletId) {
1916
+ return (await this.post({
1917
+ type: "PM_EXTERNAL_AUTH",
1918
+ payload: {
1919
+ action: "prepare",
1920
+ walletId
1921
+ }
1922
+ })).result;
1923
+ }
1924
+ async removeExternalAuth(input) {
1925
+ return (await this.post({
1926
+ type: "PM_EXTERNAL_AUTH",
1927
+ payload: {
1928
+ action: "unlink",
1929
+ walletId: input.walletId,
1930
+ associationId: input.associationId
1931
+ }
1932
+ })).result;
1933
+ }
1934
+ async associateExternalAuth(input) {
1935
+ return (await this.post({
1936
+ type: "PM_EXTERNAL_AUTH",
1937
+ payload: {
1938
+ action: "associate",
1939
+ walletId: input.walletId,
1940
+ idToken: input.idToken
1941
+ }
1942
+ })).result;
1943
+ }
1906
1944
  async getWalletSession(walletId) {
1907
1945
  const expectedWalletId = walletId === void 0 ? void 0 : parseRequestedWalletId(walletId);
1908
1946
  if (!this.state.ready || !this.state.port) await this.init();
@@ -3,6 +3,10 @@ import { walletIframeUnlockRequestFromLoginHooks } from "../shared/unlockOptions
3
3
  //#region src/SeamsWeb/walletIframe/client/sessionCommands.ts
4
4
  function createApplicationSessionCommands(walletIframe) {
5
5
  return {
6
+ authenticate: authenticate.bind(null, walletIframe),
7
+ prepareExternalAuth: prepareExternalAuth.bind(null, walletIframe),
8
+ associateExternalAuth: associateExternalAuth.bind(null, walletIframe),
9
+ removeExternalAuth: removeExternalAuth.bind(null, walletIframe),
6
10
  unlock: unlock.bind(null, walletIframe),
7
11
  unlockWithAuthMethod: unlockWithAuthMethod.bind(null, walletIframe),
8
12
  lock: lock.bind(null, walletIframe),
@@ -11,6 +15,18 @@ function createApplicationSessionCommands(walletIframe) {
11
15
  hasPasskey: hasPasskey.bind(null, walletIframe)
12
16
  };
13
17
  }
18
+ async function authenticate(walletIframe, input) {
19
+ return (await walletIframe.requireRouter()).authenticate(input);
20
+ }
21
+ async function prepareExternalAuth(walletIframe, walletId) {
22
+ return (await walletIframe.requireRouter()).prepareExternalAuth(walletId);
23
+ }
24
+ async function associateExternalAuth(walletIframe, input) {
25
+ return (await walletIframe.requireRouter()).associateExternalAuth(input);
26
+ }
27
+ async function removeExternalAuth(walletIframe, input) {
28
+ return (await walletIframe.requireRouter()).removeExternalAuth(input);
29
+ }
14
30
  async function unlock(walletIframe, walletId, options) {
15
31
  const resolvedWalletId = String(walletId || "").trim();
16
32
  if (!resolvedWalletId) throw new Error("unlock requires walletId");
@@ -44,6 +44,7 @@ function walletForHostRequest(request, currentWalletId) {
44
44
  case "PM_REGISTER_WALLET":
45
45
  case "PM_UNLOCK":
46
46
  case "PM_UNLOCK_AUTH_METHOD":
47
+ case "PM_EXTERNAL_AUTH":
47
48
  case "PM_LOCK":
48
49
  case "PM_LOCK_EXACT_WALLET_SESSION":
49
50
  case "PM_GET_LAST_WALLET_MOVE_REQUEST":
@@ -6,6 +6,7 @@ import "../../../shared-ts/src/device-linking/activeWalletSession.js";
6
6
  import { parseWalletAuthAuthorityRef } from "../../../shared-ts/src/utils/walletAuthAuthority.js";
7
7
  import { toAccountId } from "../../../core/types/accountIds.js";
8
8
  import { isWalletAuthMethod } from "../../../shared-ts/src/utils/signerDomain.js";
9
+ import { parseExternalWalletAuthentication, parseExternalWalletSettings } from "../../../shared-ts/src/auth/externalAuth.js";
9
10
  import { NonceCoordinatorDegradationReason, NonceCoordinatorFallback, NonceLeaseState } from "../../../core/signingEngine/nonce/nonceTypes.js";
10
11
  import { parseEcdsaThresholdKeyId } from "../../../core/signingEngine/session/keyMaterialBrands.js";
11
12
  import { parseNearEd25519SigningKeyId } from "../../../shared-ts/src/utils/registrationIds.js";
@@ -89,12 +90,33 @@ function parseWalletIframeExactSessionState(value) {
89
90
  function parseWalletSessionFromBoundary(value, expectedWalletId) {
90
91
  if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Wallet Session must be an object");
91
92
  if (Reflect.get(value, "reusableWalletSession") !== void 0) throw new Error("Wallet Session contains removed reusable-session fields");
92
- const parsed = {
93
- appIdentity: parseWalletSessionAppIdentity(Reflect.get(value, "appIdentity")),
94
- authentication: parseWalletAuthenticationState(Reflect.get(value, "authentication")),
95
- capabilityProjection: parseWalletSessionCapabilityProjection(Reflect.get(value, "capabilityProjection")),
93
+ const appIdentity = parseWalletSessionAppIdentity(Reflect.get(value, "appIdentity"));
94
+ const authentication = parseWalletAuthenticationState(Reflect.get(value, "authentication"));
95
+ const capabilityProjection = parseWalletSessionCapabilityProjection(Reflect.get(value, "capabilityProjection"));
96
+ const common = {
97
+ appIdentity,
96
98
  nonceDiagnostics: parseNullableNonceDiagnostics(Reflect.get(value, "nonceDiagnostics"))
97
99
  };
100
+ let parsed;
101
+ if (authentication.kind === "external_authenticated") {
102
+ if (appIdentity.kind !== "resolved") throw new Error("External authentication requires a resolved wallet");
103
+ if (common.nonceDiagnostics !== null) throw new Error("External authentication has no signing runtime");
104
+ if (capabilityProjection.kind !== "not_requested") throw new Error("External authentication cannot grant signing capabilities");
105
+ const externalSettings = parseExternalWalletSettings(Reflect.get(value, "externalSettings"));
106
+ if (externalSettings.authentication.sessionId !== authentication.sessionId || externalSettings.authentication.walletId !== authentication.walletId || externalSettings.authentication.associationId !== authentication.associationId || externalSettings.authentication.environmentId !== authentication.environmentId || externalSettings.authentication.expiresAtMs !== authentication.expiresAtMs) throw new Error("External settings identity mismatch");
107
+ parsed = {
108
+ appIdentity,
109
+ nonceDiagnostics: common.nonceDiagnostics,
110
+ authentication,
111
+ capabilityProjection,
112
+ externalSettings
113
+ };
114
+ } else parsed = {
115
+ appIdentity: common.appIdentity,
116
+ nonceDiagnostics: common.nonceDiagnostics,
117
+ authentication,
118
+ capabilityProjection
119
+ };
98
120
  const expected = expectedWalletId === void 0 ? null : requireWalletId(expectedWalletId);
99
121
  const canonicalWalletId = walletSessionCanonicalWalletId(parsed);
100
122
  if (expected !== null && canonicalWalletId === null) throw new Error("Wallet iframe Wallet Session omitted the requested wallet identity");
@@ -106,6 +128,7 @@ function parseWalletAuthenticationState(value) {
106
128
  if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Wallet Session authentication must be an object");
107
129
  switch (Reflect.get(value, "kind")) {
108
130
  case "signed_out": return { kind: "signed_out" };
131
+ case "external_authenticated": return parseExternalWalletAuthentication(value);
109
132
  case "authenticated": {
110
133
  const authMethod = Reflect.get(value, "authMethod");
111
134
  if (!isWalletAuthMethod(authMethod)) throw new Error("Wallet Session authentication method is invalid");
@@ -470,7 +470,7 @@ function parseHostedAuthMenuOutcome(value) {
470
470
  default: return null;
471
471
  }
472
472
  }
473
- const WALLET_PROTOCOL_VERSION = "17.0.0";
473
+ const WALLET_PROTOCOL_VERSION = "18.0.0";
474
474
  const WALLET_IFRAME_PROTOCOL_VERSION_MISMATCH = "WALLET_IFRAME_PROTOCOL_VERSION_MISMATCH";
475
475
  const HOSTED_WALLET_REDEMPTION_PAYLOAD_FIELDS = [
476
476
  "home",
@@ -5,12 +5,18 @@ function parseWalletAuthMethodPlugins(value) {
5
5
  const plugins = [];
6
6
  const seen = /* @__PURE__ */ new Set();
7
7
  for (const candidate of value) {
8
- if (!isPlainObject(candidate) || Object.keys(candidate).length !== 1 || candidate.kind !== "voiceid" || seen.has(candidate.kind)) throw new Error("Unsupported or duplicate wallet auth method plugin.");
8
+ if (!isPlainObject(candidate) || Object.keys(candidate).some(unknownVoiceIdOption) || candidate.kind !== "voiceid" || candidate.transcriptionModel !== void 0 && candidate.transcriptionModel !== "aurora" && candidate.transcriptionModel !== "citrinet" || seen.has(candidate.kind)) throw new Error("Unsupported or duplicate wallet auth method plugin.");
9
9
  seen.add(candidate.kind);
10
- plugins.push({ kind: "voiceid" });
10
+ plugins.push({
11
+ kind: "voiceid",
12
+ transcriptionModel: candidate.transcriptionModel ?? "citrinet"
13
+ });
11
14
  }
12
15
  return plugins;
13
16
  }
17
+ function unknownVoiceIdOption(key) {
18
+ return key !== "kind" && key !== "transcriptionModel";
19
+ }
14
20
  //#endregion
15
21
  export { parseWalletAuthMethodPlugins };
16
22
 
@@ -305,6 +305,11 @@ const walletMessages = [
305
305
  ["Dark mode", "ダークモード"],
306
306
  ["Unable to lock your wallet. Try again.", "ウォレットをロックできません。もう一度お試しください。"],
307
307
  ["Unlocked on this device", "このデバイスでロック解除済み"],
308
+ ["Connected with Google", "Google で接続中"],
309
+ ["Wallet access", "ウォレットへのアクセス"],
310
+ ["Connected to your wallet", "ウォレットに接続しています"],
311
+ ["Method {value0}", "認証方法 {value0}"],
312
+ ["Confirm with a wallet authentication method to make security changes.", "セキュリティ設定を変更するには、ウォレットの認証方法で本人確認してください。"],
308
313
  ["All settings", "すべての設定"],
309
314
  ["Locking…", "ロック中…"],
310
315
  ["Lock wallet", "ウォレットをロック"],
@@ -4,7 +4,7 @@ import { WalletText, useWalletLocale } from "../../context/WalletLocale.js";
4
4
  import TouchIcon from "./icons/TouchIcon.js";
5
5
  import { UserAccountButton } from "./UserAccountButton.js";
6
6
  import { ProfileDropdown } from "./ProfileDropdown.js";
7
- import { AccountMenuModal } from "./AccountMenuModal.js";
7
+ import { AccountSettingsDialog } from "./AccountSettingsDialog.js";
8
8
  import { LockKeyholeIcon } from "./icons/LockKeyholeIcon.js";
9
9
  import { useLayoutEffect, useRef, useState } from "react";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -13,9 +13,9 @@ import "./Web3AuthProfileButton.css";
13
13
  function measurePanel(element, setHeight) {
14
14
  setHeight(element.offsetHeight);
15
15
  }
16
- function observePanel(contentRef, isOpen, setHeight) {
16
+ function observePanel(contentRef, isOpen, presentation, setHeight) {
17
17
  const content = contentRef.current;
18
- if (!content || !isOpen) {
18
+ if (!content || !isOpen || presentation === "drawer") {
19
19
  setHeight(null);
20
20
  return;
21
21
  }
@@ -28,14 +28,14 @@ function observePanel(contentRef, isOpen, setHeight) {
28
28
  function closeWithEscape(presentation, onClose, event) {
29
29
  if (event.key !== "Escape" || event.defaultPrevented) return;
30
30
  event.preventDefault();
31
- if (presentation === "modal") event.stopPropagation();
31
+ if (presentation !== "dropdown") event.stopPropagation();
32
32
  onClose();
33
33
  }
34
- function revealModalScreen(presentation, event) {
35
- if (presentation !== "modal" || !(event.target instanceof HTMLElement)) return;
34
+ function revealDialogScreen(presentation, event) {
35
+ if (presentation === "dropdown" || !(event.target instanceof HTMLElement)) return;
36
36
  if (!event.target.matches(".seams-account-heading h2, .seams-account-identity")) return;
37
- const dialog = event.currentTarget.closest("dialog.seams-account-modal");
38
- if (dialog instanceof HTMLDialogElement) dialog.scrollTop = 0;
37
+ const scrollArea = presentation === "drawer" ? event.target.closest(".seams-account-main") : event.currentTarget.closest("dialog.seams-account-dialog");
38
+ if (scrollArea) scrollArea.scrollTop = 0;
39
39
  }
40
40
  function restoreTriggerFocus(buttonRef, previousOpen, isOpen) {
41
41
  if (previousOpen.current && !isOpen) buttonRef.current?.querySelector("[aria-expanded]")?.focus({ preventScroll: true });
@@ -55,20 +55,21 @@ function AccountMenuButtonView({ presentation, buttonRef, dropdownRef, trigger,
55
55
  const previousOpen = useRef(trigger.isOpen);
56
56
  useLayoutEffect(restoreTriggerFocus.bind(null, buttonRef, previousOpen, trigger.isOpen), [buttonRef, trigger.isOpen]);
57
57
  const [height, setHeight] = useState(null);
58
- useLayoutEffect(observePanel.bind(null, contentRef, trigger.isOpen, setHeight), [trigger.isOpen, presentation]);
58
+ useLayoutEffect(observePanel.bind(null, contentRef, trigger.isOpen, presentation, setHeight), [trigger.isOpen, presentation]);
59
+ const panelOpen = presentation !== "dropdown" || trigger.isOpen;
59
60
  const panel = /* @__PURE__ */ jsx("div", {
60
61
  ref: buttonRef,
61
- className: `seams-profile-button-morphable ${trigger.isOpen ? "open" : "closed"} ${className ?? ""}`,
62
- style: trigger.isOpen ? style : {
62
+ className: `seams-profile-button-morphable ${panelOpen ? "open" : "closed"} ${className ?? ""}`,
63
+ style: panelOpen ? style : {
63
64
  ...style,
64
65
  width: "fit-content"
65
66
  },
66
- "data-state": trigger.isOpen ? "open" : "closed",
67
- onFocusCapture: revealModalScreen.bind(null, presentation),
68
- children: trigger.isOpen ? /* @__PURE__ */ jsx("div", {
67
+ "data-state": panelOpen ? "open" : "closed",
68
+ onFocusCapture: revealDialogScreen.bind(null, presentation),
69
+ children: panelOpen ? /* @__PURE__ */ jsx("div", {
69
70
  className: "seams-account-resize",
70
71
  onKeyDown: closeWithEscape.bind(null, presentation, dropdown.onClose),
71
- style: { height: height ?? void 0 },
72
+ style: { height: presentation === "drawer" ? void 0 : height ?? void 0 },
72
73
  children: /* @__PURE__ */ jsxs("div", {
73
74
  ref: contentRef,
74
75
  className: "seams-account-panel-content",
@@ -92,7 +93,11 @@ function AccountMenuButtonView({ presentation, buttonRef, dropdownRef, trigger,
92
93
  strokeWidth: "1.5",
93
94
  children: /* @__PURE__ */ jsx("path", { d: "m6 6 12 12M18 6 6 18" })
94
95
  })
95
- })
96
+ }),
97
+ presentation === "drawer" ? /* @__PURE__ */ jsx("h2", {
98
+ className: "seams-account-drawer-title",
99
+ children: /* @__PURE__ */ jsx(WalletText, { message: "Wallet settings" })
100
+ }) : null
96
101
  ]
97
102
  }),
98
103
  /* @__PURE__ */ jsx("div", {
@@ -131,12 +136,20 @@ function AccountMenuButtonView({ presentation, buttonRef, dropdownRef, trigger,
131
136
  })
132
137
  }) : /* @__PURE__ */ jsx(UserAccountButton, { ...trigger })
133
138
  });
134
- if (presentation === "modal") return /* @__PURE__ */ jsx(AccountMenuModal, {
135
- isOpen: trigger.isOpen,
136
- onClose: dropdown.onClose,
137
- children: panel
138
- });
139
- return panel;
139
+ switch (presentation) {
140
+ case "dropdown": return panel;
141
+ case "modal":
142
+ case "drawer": return /* @__PURE__ */ jsx(AccountSettingsDialog, {
143
+ presentation,
144
+ isOpen: trigger.isOpen,
145
+ onClose: dropdown.onClose,
146
+ children: panel
147
+ });
148
+ default: return assertNever(presentation);
149
+ }
150
+ }
151
+ function assertNever(value) {
152
+ throw new Error(`Unsupported account menu presentation: ${String(value)}`);
140
153
  }
141
154
  //#endregion
142
155
  export { AccountMenuButtonView };
@@ -0,0 +1,157 @@
1
+ import { walletText } from "../../../core/ui/messages.js";
2
+ import { useWalletLocale } from "../../context/WalletLocale.js";
3
+ import { Theme, useTheme } from "../theme/ThemeProvider.js";
4
+ import { Component } from "react";
5
+ import { createPortal } from "react-dom";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/react/components/AccountMenuButton/AccountSettingsDialog.tsx
8
+ const DRAWER_DURATION_MS = 240;
9
+ const DRAWER_EASING = "cubic-bezier(0.32, 0.72, 0, 1)";
10
+ function ignoreCancelledAnimation() {}
11
+ function assertNever(value) {
12
+ throw new Error(`Unsupported settings dialog state: ${String(value)}`);
13
+ }
14
+ function isBackdrop(event) {
15
+ if (event.target !== event.currentTarget) return false;
16
+ const bounds = event.currentTarget.getBoundingClientRect();
17
+ return event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom;
18
+ }
19
+ var SettingsDialog = class extends Component {
20
+ state = { dialog: { kind: "closed" } };
21
+ dialog = null;
22
+ motion = null;
23
+ startedOutside = false;
24
+ static getDerivedStateFromProps(props, state) {
25
+ if (props.isOpen) return { dialog: {
26
+ kind: "open",
27
+ content: props.children
28
+ } };
29
+ switch (state.dialog.kind) {
30
+ case "closed": return null;
31
+ case "open":
32
+ if (props.presentation === "modal") return { dialog: { kind: "closed" } };
33
+ return { dialog: {
34
+ kind: "closing",
35
+ content: state.dialog.content
36
+ } };
37
+ case "closing": return props.presentation === "modal" ? { dialog: { kind: "closed" } } : null;
38
+ default: return assertNever(state.dialog);
39
+ }
40
+ }
41
+ componentDidMount() {
42
+ this.syncDialog("closed", this.props.presentation);
43
+ }
44
+ componentDidUpdate(previousProps, previousState) {
45
+ this.syncDialog(previousState.dialog.kind, previousProps.presentation);
46
+ }
47
+ componentWillUnmount() {
48
+ this.clearMotion();
49
+ this.dialog?.close();
50
+ }
51
+ setDialog = (dialog) => {
52
+ if (dialog === this.dialog) return;
53
+ this.clearMotion();
54
+ this.dialog?.close();
55
+ this.dialog = dialog;
56
+ };
57
+ clearMotion() {
58
+ this.motion?.cancel();
59
+ this.motion = null;
60
+ }
61
+ syncDialog(previous, presentation) {
62
+ const dialog = this.dialog;
63
+ if (!dialog) return;
64
+ dialog.inert = this.state.dialog.kind === "closing";
65
+ if (!dialog.open) dialog.showModal();
66
+ if (this.props.presentation === "modal") {
67
+ this.clearMotion();
68
+ return;
69
+ }
70
+ if (previous === this.state.dialog.kind && presentation === this.props.presentation) return;
71
+ if (previous === "closing" && this.state.dialog.kind === "open") dialog.querySelector(".seams-account-close")?.focus({ preventScroll: true });
72
+ this.animateDrawer(previous === "closed" || presentation !== this.props.presentation);
73
+ }
74
+ animateDrawer(entering) {
75
+ const dialog = this.dialog;
76
+ if (!dialog) return;
77
+ const computed = getComputedStyle(dialog);
78
+ const offset = computed.getPropertyValue("--seams-account-drawer-offset").trim();
79
+ const from = entering ? offset : computed.transform;
80
+ this.clearMotion();
81
+ if (matchMedia("(prefers-reduced-motion: reduce)").matches) {
82
+ if (this.state.dialog.kind === "closing") this.setState({ dialog: { kind: "closed" } });
83
+ return;
84
+ }
85
+ const to = this.state.dialog.kind === "closing" ? offset : "none";
86
+ const animation = dialog.animate([{ transform: from }, { transform: to }], {
87
+ duration: DRAWER_DURATION_MS,
88
+ easing: DRAWER_EASING,
89
+ fill: "both"
90
+ });
91
+ this.motion = animation;
92
+ animation.finished.then(this.finishMotion.bind(this, animation), ignoreCancelledAnimation);
93
+ }
94
+ finishMotion(animation) {
95
+ if (this.motion !== animation) return;
96
+ if (this.state.dialog.kind === "closing") {
97
+ this.setState({ dialog: { kind: "closed" } });
98
+ return;
99
+ }
100
+ this.clearMotion();
101
+ }
102
+ requestClose = () => {
103
+ if (this.state.dialog.kind === "open") this.props.onClose();
104
+ };
105
+ rememberBackdrop = (event) => {
106
+ this.startedOutside = isBackdrop(event);
107
+ };
108
+ closeBackdrop = (event) => {
109
+ const shouldClose = this.startedOutside && isBackdrop(event);
110
+ this.startedOutside = false;
111
+ if (!shouldClose) return;
112
+ event.stopPropagation();
113
+ this.requestClose();
114
+ };
115
+ cancelDialog = (event) => {
116
+ event.preventDefault();
117
+ event.stopPropagation();
118
+ this.requestClose();
119
+ };
120
+ render() {
121
+ if (this.state.dialog.kind === "closed" || typeof document === "undefined") return null;
122
+ return createPortal(/* @__PURE__ */ jsx(Theme, {
123
+ tag: "div",
124
+ theme: this.props.theme,
125
+ tokens: { [this.props.theme]: this.props.tokens },
126
+ children: /* @__PURE__ */ jsx("dialog", {
127
+ ref: this.setDialog,
128
+ "data-seams-root": "",
129
+ "data-presentation": this.props.presentation,
130
+ "data-state": this.state.dialog.kind,
131
+ className: "seams-account-dialog",
132
+ "aria-label": this.props.label,
133
+ onCancel: this.cancelDialog,
134
+ onPointerDown: this.rememberBackdrop,
135
+ onClick: this.closeBackdrop,
136
+ children: this.state.dialog.content
137
+ })
138
+ }), document.body);
139
+ }
140
+ };
141
+ function AccountSettingsDialog(props) {
142
+ const locale = useWalletLocale();
143
+ const { theme, tokens } = useTheme();
144
+ return /* @__PURE__ */ jsx(SettingsDialog, {
145
+ presentation: props.presentation,
146
+ isOpen: props.isOpen,
147
+ onClose: props.onClose,
148
+ theme,
149
+ tokens,
150
+ label: walletText(locale, "Wallet settings"),
151
+ children: props.children
152
+ });
153
+ }
154
+ //#endregion
155
+ export { AccountSettingsDialog };
156
+
157
+ //# sourceMappingURL=AccountSettingsDialog.js.map
@@ -2,6 +2,7 @@ import { walletDisplayText, walletText } from "../../../core/ui/messages.js";
2
2
  import { WalletText, useWalletLocale } from "../../context/WalletLocale.js";
3
3
  import { useSeams } from "../../context/index.js";
4
4
  import { AccountMenuDialogFrame } from "./AccountMenuDialog.js";
5
+ import { ExternalWalletSettingsView } from "./ExternalWalletSettings.js";
5
6
  import { AuthenticationMethodRow } from "./AuthenticationMethodRow.js";
6
7
  import { VoiceIdMethodRow, VoiceIdSetupRow } from "./VoiceIdAvailabilityControl.js";
7
8
  import { AuthenticationMethodsView } from "./AuthenticationMethodsView.js";
@@ -115,7 +116,18 @@ function methodDescription(method) {
115
116
  case "voiceid": return "Voice unlock on this device";
116
117
  }
117
118
  }
118
- const AuthenticationMethodsModal = ({ walletId, isOpen, onClose, presentation }) => {
119
+ function AuthenticationMethodsModal(props) {
120
+ const { loginState } = useSeams();
121
+ if (!props.isOpen) return null;
122
+ if (loginState.isLoggedIn && loginState.access === "external") return /* @__PURE__ */ jsx(ExternalWalletSettingsView, {
123
+ settings: loginState.externalSettings,
124
+ view: "methods",
125
+ presentation: props.presentation,
126
+ onClose: props.onClose
127
+ });
128
+ return /* @__PURE__ */ jsx(OwnerAuthenticationMethodsModal, { ...props });
129
+ }
130
+ const OwnerAuthenticationMethodsModal = ({ walletId, isOpen, onClose, presentation }) => {
119
131
  const locale = useWalletLocale();
120
132
  const { seams, loginState, refreshSession } = useSeams();
121
133
  const [loadState, setLoadState] = React.useState({ kind: "idle" });
@@ -0,0 +1,46 @@
1
+ import { walletText } from "../../../core/ui/messages.js";
2
+ import { WalletText, useWalletLocale } from "../../context/WalletLocale.js";
3
+ import { AccountMenuDialogFrame } from "./AccountMenuDialog.js";
4
+ import { AccountMenuDeviceDetails } from "./AccountMenuDeviceDetails.js";
5
+ import { useRef } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/react/components/AccountMenuButton/ExternalWalletSettings.tsx
8
+ function ExternalWalletSettingsView(props) {
9
+ const locale = useWalletLocale();
10
+ const ref = useRef(null);
11
+ const title = props.view === "methods" ? "Authentication methods" : "Linked devices";
12
+ const details = props.view === "methods" ? props.settings.methods.map(methodDetail.bind(null, locale)) : props.settings.devices.map(deviceDetail.bind(null, locale));
13
+ return /* @__PURE__ */ jsxs(AccountMenuDialogFrame, {
14
+ presentation: props.presentation,
15
+ onClose: props.onClose,
16
+ dialogRef: ref,
17
+ contentClassName: "",
18
+ titleId: `external-wallet-${props.view}`,
19
+ title,
20
+ children: [/* @__PURE__ */ jsx(AccountMenuDeviceDetails, {
21
+ title: "Wallet access",
22
+ description: "Connected to your wallet",
23
+ details
24
+ }), /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(WalletText, { message: "Confirm with a wallet authentication method to make security changes." }) })]
25
+ });
26
+ }
27
+ function methodDetail(locale, method, index) {
28
+ return {
29
+ label: walletText(locale, "Method {value0}", { value0: index + 1 }),
30
+ value: {
31
+ passkey: "Passkey",
32
+ email_otp: "Email code",
33
+ voiceid: "VoiceID"
34
+ }[method.kind]
35
+ };
36
+ }
37
+ function deviceDetail(locale, _device, index) {
38
+ return {
39
+ label: walletText(locale, "Device {value0}", { value0: index + 1 }),
40
+ value: "Active"
41
+ };
42
+ }
43
+ //#endregion
44
+ export { ExternalWalletSettingsView };
45
+
46
+ //# sourceMappingURL=ExternalWalletSettings.js.map
@@ -1,8 +1,9 @@
1
1
  import { walletDisplayText, walletText } from "../../../core/ui/messages.js";
2
2
  import { WalletText, useWalletLocale } from "../../context/WalletLocale.js";
3
3
  import { useSeams } from "../../context/index.js";
4
- import { AccountMenuDeviceDetails } from "./AccountMenuDeviceDetails.js";
5
4
  import { AccountMenuDialogFrame } from "./AccountMenuDialog.js";
5
+ import { AccountMenuDeviceDetails } from "./AccountMenuDeviceDetails.js";
6
+ import { ExternalWalletSettingsView } from "./ExternalWalletSettings.js";
6
7
  import { MailIcon } from "./icons/MailIcon.js";
7
8
  import { AuthenticationMethodRow } from "./AuthenticationMethodRow.js";
8
9
  import { LaptopIcon } from "./icons/LaptopIcon.js";
@@ -214,7 +215,18 @@ function withLinkedDevicesLoadTimeout(promise) {
214
215
  });
215
216
  });
216
217
  }
217
- const LinkedDevicesModal = ({ walletId, isOpen, onClose, presentation }) => {
218
+ function LinkedDevicesModal(props) {
219
+ const { loginState } = useSeams();
220
+ if (!props.isOpen) return null;
221
+ if (loginState.isLoggedIn && loginState.access === "external") return /* @__PURE__ */ jsx(ExternalWalletSettingsView, {
222
+ settings: loginState.externalSettings,
223
+ view: "devices",
224
+ presentation: props.presentation,
225
+ onClose: props.onClose
226
+ });
227
+ return /* @__PURE__ */ jsx(OwnerLinkedDevicesModal, { ...props });
228
+ }
229
+ const OwnerLinkedDevicesModal = ({ walletId, isOpen, onClose, presentation }) => {
218
230
  const locale = useWalletLocale();
219
231
  const { seams, loginState } = useSeams();
220
232
  const [loadState, setLoadState] = React.useState({ kind: "idle" });
@@ -182,7 +182,7 @@ var WalletSettingsLayout = class extends Component {
182
182
  children: [
183
183
  /* @__PURE__ */ jsxs("div", {
184
184
  className: "seams-settings-identity",
185
- children: [/* @__PURE__ */ jsx(TouchIcon, {}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: this.props.walletId }), /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(WalletText, { message: "Unlocked on this device" }) })] })]
185
+ children: [/* @__PURE__ */ jsx(TouchIcon, {}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: this.props.walletId }), /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(WalletText, { copy: this.props.access === "external" ? "Connected with Google" : "Unlocked on this device" }) })] })]
186
186
  }),
187
187
  /* @__PURE__ */ jsx("button", {
188
188
  className: "seams-settings-mobile-toggle",