@asseteragmbh/wallet-connector 0.2.1 → 0.2.3

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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { ProviderRpcError, createAsseteraWalletProvider } from './chunk-YJHLKN7O.js';
2
- import { isCaip2EvmChain, onboardUrl, manageUrl, isOnboardedMessage, isOnboardCancelledMessage, isSecurityMessage, isResponseMessage, RpcErrorCode, PROTOCOL_VERSION, MESSAGE_PREFIX } from './chunk-H7PEM735.js';
3
- export { CONNECT_PATH, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, PROTOCOL_VERSION, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl } from './chunk-H7PEM735.js';
1
+ export { ProviderRpcError, createAsseteraWalletProvider } from './chunk-RAR3QQGK.js';
2
+ import { isCaip2EvmChain, onboardUrl, manageUrl, isOnboardedMessage, isOnboardCancelledMessage, isSecurityMessage, isAccountsMessage, isResponseMessage, RpcErrorCode, PROTOCOL_VERSION, MESSAGE_PREFIX } from './chunk-ZEOGKINA.js';
3
+ export { CONNECT_PATH, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, PROTOCOL_VERSION, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, connectUrl, isAccountsMessage, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl } from './chunk-ZEOGKINA.js';
4
4
 
5
5
  // src/popup.ts
6
6
  var POPUP_WIDTH = 440;
@@ -56,6 +56,9 @@ function cancelMessage(reason) {
56
56
  if (reason === "refused") return "The Assetera Wallet refused the onboarding.";
57
57
  return "The Assetera Wallet onboarding failed.";
58
58
  }
59
+ function copyAccountNames(accounts) {
60
+ return accounts.map((account) => ({ address: account.address, name: account.name }));
61
+ }
59
62
  function showOverlay(win, labels, handlers) {
60
63
  const doc = win.document;
61
64
  const root = doc.createElement("div");
@@ -224,6 +227,7 @@ function openAsseteraOnboarding(options) {
224
227
  });
225
228
  }
226
229
  let address;
230
+ let lastAccountNameList;
227
231
  function onMessage(event) {
228
232
  if (event.origin !== walletOrigin) return;
229
233
  if (event.source !== activePopup) return;
@@ -237,7 +241,8 @@ function openAsseteraOnboarding(options) {
237
241
  chain: data.chain,
238
242
  created: data.created ?? true,
239
243
  signMessage,
240
- close
244
+ close,
245
+ lastAccounts: () => lastAccountNameList === void 0 ? void 0 : copyAccountNames(lastAccountNameList)
241
246
  });
242
247
  return;
243
248
  }
@@ -246,6 +251,11 @@ function openAsseteraOnboarding(options) {
246
251
  }
247
252
  return;
248
253
  }
254
+ if (isAccountsMessage(data)) {
255
+ lastAccountNameList = copyAccountNames(data.data);
256
+ options.onAccounts?.(copyAccountNames(lastAccountNameList));
257
+ return;
258
+ }
249
259
  if (isResponseMessage(data)) {
250
260
  const entry = pending.get(data.id);
251
261
  if (!entry) return;
@@ -324,6 +334,7 @@ function openAsseteraWalletManager(options) {
324
334
  const activePopup = popup;
325
335
  let finished = false;
326
336
  let lastSecurity;
337
+ let lastAccounts;
327
338
  let closeTimer = null;
328
339
  let resolveClosed;
329
340
  const closed = new Promise((resolve) => {
@@ -343,18 +354,27 @@ function openAsseteraWalletManager(options) {
343
354
  cleanup();
344
355
  if (!activePopup.closed) activePopup.close();
345
356
  }
357
+ function copyAccountNames2(accounts) {
358
+ return accounts.map((account) => ({ address: account.address, name: account.name }));
359
+ }
346
360
  function onMessage(event) {
347
361
  if (event.origin !== walletOrigin) return;
348
362
  if (event.source !== activePopup) return;
349
363
  const data = event.data;
350
- if (!isSecurityMessage(data)) return;
351
- const status = {
352
- protection: data.data.protection,
353
- passkeys: data.data.passkeys,
354
- authenticatorApps: data.data.authenticatorApps
355
- };
356
- lastSecurity = status;
357
- options.onSecurity?.(status);
364
+ if (isSecurityMessage(data)) {
365
+ const status = {
366
+ protection: data.data.protection,
367
+ passkeys: data.data.passkeys,
368
+ authenticatorApps: data.data.authenticatorApps
369
+ };
370
+ lastSecurity = status;
371
+ options.onSecurity?.(status);
372
+ return;
373
+ }
374
+ if (isAccountsMessage(data)) {
375
+ lastAccounts = copyAccountNames2(data.data);
376
+ options.onAccounts?.(copyAccountNames2(lastAccounts));
377
+ }
358
378
  }
359
379
  targetWindow.addEventListener("message", onMessage);
360
380
  closeTimer = setInterval(() => {
@@ -363,7 +383,8 @@ function openAsseteraWalletManager(options) {
363
383
  return {
364
384
  close,
365
385
  closed,
366
- lastSecurity: () => lastSecurity
386
+ lastSecurity: () => lastSecurity,
387
+ lastAccounts: () => lastAccounts === void 0 ? void 0 : copyAccountNames2(lastAccounts)
367
388
  };
368
389
  }
369
390
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/popup.ts","../src/onboarding.ts","../src/manage.ts"],"names":["POPUP_NAME","CLOSE_POLL_MS"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Small helpers shared by the pop-up openers in this package. They are internal and are not part of the public\n * API through `index.ts`.\n */\n\n/** Default width, in pixels, of the onboarding and manage pop-ups. */\nexport const POPUP_WIDTH = 440;\n\n/** Default height, in pixels, of the onboarding and manage pop-ups. */\nexport const POPUP_HEIGHT = 760;\n\n/**\n * Build the centred `window.open` feature string for a pop-up of the default size. `win` is the opener window:\n * the pop-up is centred over it, and safe defaults are used when the browser does not expose the geometry.\n */\nexport function defaultPopupFeatures(win: Window): string {\n const screenX = Number.isFinite(win.screenX) ? win.screenX : 0;\n const screenY = Number.isFinite(win.screenY) ? win.screenY : 0;\n const outerWidth = Number.isFinite(win.outerWidth) ? win.outerWidth : POPUP_WIDTH;\n const outerHeight = Number.isFinite(win.outerHeight) ? win.outerHeight : POPUP_HEIGHT;\n const left = Math.max(0, Math.round(screenX + (outerWidth - POPUP_WIDTH) / 2));\n const top = Math.max(0, Math.round(screenY + (outerHeight - POPUP_HEIGHT) / 2));\n return `popup,width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top}`;\n}\n","/**\n * Onboarding opener for the Assetera Wallet: the partner side of the `/onboard` wizard (AO-1274).\n *\n * A tied-agent bank site shows a \"Create an Assetera wallet\" button. On the click, this module opens the wallet\n * pop-up in onboarding mode synchronously (so the browser treats it as part of the click) and waits for the\n * wizard to post the new wallet address back. While the pop-up is open the partner page shows a dimming\n * overlay; the overlay is plain DOM (no React, no CSS files) so any partner can drop this in.\n *\n * The wallet's `/onboard` page is the pop-up side and speaks the same protocol in `./protocol`, but it uses the\n * message types and the `ONBOARD_PATH` from there, so the two sides cannot drift apart.\n */\nimport {\n MESSAGE_PREFIX,\n PROTOCOL_VERSION,\n RpcErrorCode,\n isCaip2EvmChain,\n isOnboardCancelledMessage,\n isOnboardedMessage,\n isResponseMessage,\n onboardUrl,\n type OnboardCancelledMessage,\n type RequestMessage,\n type SignInHint,\n} from \"./protocol\";\nimport { defaultPopupFeatures } from \"./popup\";\n\n/** Why {@link openAsseteraOnboarding} rejected. */\nexport type OnboardingErrorCode =\n \"popup_blocked\" | \"closed\" | \"cancelled\" | \"refused\" | \"failed\" | \"invalid_options\";\n\n/** Error thrown (well, rejected) by {@link openAsseteraOnboarding}. `code` is stable and safe to branch on. */\nexport class OnboardingError extends Error {\n readonly code: OnboardingErrorCode;\n\n constructor(code: OnboardingErrorCode, message: string) {\n super(message);\n this.name = \"OnboardingError\";\n this.code = code;\n }\n}\n\n/**\n * The client's Assetera Wallet, with the pop-up still open.\n *\n * The wallet is NOT registered with any compliance service. A regulated partner registers it itself, like any\n * other wallet: fetch a challenge for `address`, pass it to `signMessage`, send the signature to its compliance\n * service, then call `close()`. Always call `close()`: it closes the pop-up and removes the overlay.\n */\nexport interface OnboardingResult {\n address: `0x${string}`;\n chain: string;\n /** `true` when the wallet was created in this run, `false` when the client's existing wallet was returned. */\n created: boolean;\n /**\n * Ask the client to sign `message` (EIP-191 `personal_sign`) with this wallet in the open pop-up. Rejects with\n * `OnboardingError(\"cancelled\")` when the client declines, `\"closed\"` when the pop-up is gone, else `\"failed\"`.\n */\n signMessage: (message: string) => Promise<`0x${string}`>;\n /** Close the pop-up and remove the overlay. Safe to call more than once. */\n close: () => void;\n}\n\n/** Text of the dimming overlay, all optional. Any key left out keeps its English default. */\nexport interface OverlayLabels {\n title?: string;\n body?: string;\n focus?: string;\n cancel?: string;\n blocked?: string;\n}\n\n/** Options for {@link openAsseteraOnboarding}. */\nexport interface OnboardingOptions {\n /** Base URL of the wallet origin, e.g. `https://wallet.wallet-staging.assetera.com`. */\n walletUrl: string;\n /** CAIP-2 chain id the new wallet should be created on, e.g. `eip155:80002`. An invalid value rejects with `invalid_options`. */\n chain: string;\n /** Wizard language passed as `lang`, e.g. `\"en\"` or `\"de\"`. */\n locale?: string;\n /** `window.open` feature string. Defaults to a centred `\"popup,width=440,height=760,left=…,top=…\"`. */\n popupFeatures?: string;\n /** `true` (default) shows the dimming overlay, `false` hides it, an object overrides its text. */\n overlay?: boolean | OverlayLabels;\n /** Only used in the overlay text, e.g. `\"Musterbank\"`. */\n partnerName?: string;\n /** Ask for one more wallet even when the client already has one (\"Create another Assetera Wallet\"). */\n addWallet?: boolean;\n /** Sign-in hint passed as `signIn`, e.g. `\"assetera-marketplace\"`. Only a hint; the wallet may ignore it. */\n signIn?: SignInHint;\n /** Injectable `window` for tests; defaults to `globalThis.window`. */\n window?: Window;\n}\n\nconst POPUP_NAME = \"assetera-wallet-onboarding\";\nconst CLOSE_POLL_MS = 500;\nconst OVERLAY_Z_INDEX = 2147483000;\n\nconst DEFAULT_LABELS: Required<OverlayLabels> = {\n title: \"Continue in the Assetera Wallet window\",\n body: \"A secure Assetera Wallet window is open. Follow the steps there. This page continues by itself when you are done.\",\n focus: \"Show the wallet window\",\n cancel: \"Cancel\",\n blocked: \"Your browser blocked the Assetera Wallet window. Allow pop-ups for this site and try again.\",\n};\n\ninterface OverlayHandlers {\n onFocus: () => void;\n onCancel: () => void;\n}\n\nfunction resolveLabels(options: OnboardingOptions): Required<OverlayLabels> {\n const overrides: OverlayLabels =\n typeof options.overlay === \"object\" && options.overlay !== null ? options.overlay : {};\n const partnerName = options.partnerName;\n const defaultBody = partnerName\n ? `A secure Assetera Wallet window is open for ${partnerName}. Follow the steps there. This page continues by itself when you are done.`\n : DEFAULT_LABELS.body;\n return {\n title: overrides.title ?? DEFAULT_LABELS.title,\n body: overrides.body ?? defaultBody,\n focus: overrides.focus ?? DEFAULT_LABELS.focus,\n cancel: overrides.cancel ?? DEFAULT_LABELS.cancel,\n blocked: overrides.blocked ?? DEFAULT_LABELS.blocked,\n };\n}\n\nfunction cancelCode(reason: OnboardCancelledMessage[\"reason\"]): OnboardingErrorCode {\n if (reason === \"user\") return \"cancelled\";\n if (reason === \"refused\") return \"refused\";\n return \"failed\";\n}\n\nfunction cancelMessage(reason: OnboardCancelledMessage[\"reason\"]): string {\n if (reason === \"user\") return \"The user cancelled the Assetera Wallet onboarding.\";\n if (reason === \"refused\") return \"The Assetera Wallet refused the onboarding.\";\n return \"The Assetera Wallet onboarding failed.\";\n}\n\n/**\n * Build the dimming overlay. Text is inserted with `textContent` only and every style is inline, so the\n * overlay cannot pick up partner CSS and cannot be scripted through an injected string.\n */\nfunction showOverlay(win: Window, labels: Required<OverlayLabels>, handlers: OverlayHandlers): HTMLElement {\n const doc = win.document;\n const root = doc.createElement(\"div\");\n root.setAttribute(\"role\", \"dialog\");\n root.setAttribute(\"aria-modal\", \"true\");\n root.setAttribute(\"data-assetera-onboarding-overlay\", \"\");\n root.style.cssText = [\n \"position: fixed\",\n \"inset: 0\",\n \"display: flex\",\n \"align-items: center\",\n \"justify-content: center\",\n \"padding: 24px\",\n \"box-sizing: border-box\",\n \"background: rgba(15,20,30,0.6)\",\n `z-index: ${OVERLAY_Z_INDEX}`,\n \"font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n ].join(\"; \");\n\n const card = doc.createElement(\"div\");\n card.style.cssText = [\n \"box-sizing: border-box\",\n \"width: 100%\",\n \"max-width: 420px\",\n \"border-radius: 16px\",\n \"padding: 24px\",\n \"background: #ffffff\",\n \"color: #101828\",\n \"box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35)\",\n ].join(\"; \");\n\n const title = doc.createElement(\"h2\");\n title.textContent = labels.title;\n title.style.cssText = \"margin: 0 0 10px; font-size: 18px; line-height: 1.3; font-weight: 600;\";\n\n const body = doc.createElement(\"p\");\n body.textContent = labels.body;\n body.style.cssText = \"margin: 0 0 20px; font-size: 14px; line-height: 1.5; color: #475467;\";\n\n const focus = doc.createElement(\"button\");\n focus.type = \"button\";\n focus.textContent = labels.focus;\n focus.style.cssText = [\n \"padding: 10px 16px\",\n \"border: 0\",\n \"border-radius: 10px\",\n \"background: #101828\",\n \"color: #ffffff\",\n \"font: inherit\",\n \"font-weight: 600\",\n \"cursor: pointer\",\n ].join(\"; \");\n focus.addEventListener(\"click\", handlers.onFocus);\n\n const cancel = doc.createElement(\"button\");\n cancel.type = \"button\";\n cancel.textContent = labels.cancel;\n cancel.style.cssText = [\n \"padding: 10px 16px\",\n \"border: 0\",\n \"border-radius: 10px\",\n \"background: transparent\",\n \"color: #475467\",\n \"font: inherit\",\n \"cursor: pointer\",\n ].join(\"; \");\n cancel.addEventListener(\"click\", handlers.onCancel);\n\n const actions = doc.createElement(\"div\");\n actions.style.cssText = \"display: flex; gap: 8px; align-items: center;\";\n actions.append(focus, cancel);\n\n card.append(title, body, actions);\n root.append(card);\n doc.body.append(root);\n return root;\n}\n\n/**\n * Open the Assetera Wallet onboarding wizard in a pop-up and resolve with the client's wallet, the pop-up still\n * open so the partner can ask for the ownership signature (see {@link OnboardingResult}).\n *\n * Call this from a user click (a button handler). `window.open` runs synchronously inside the call, before any\n * `await`, so the browser allows it; if the browser blocks the pop-up the promise rejects with\n * `OnboardingError(\"popup_blocked\")` and no overlay is shown.\n *\n * The promise rejects with `OnboardingError` and one of these codes: `invalid_options` (bad chain or wallet\n * URL), `popup_blocked`, `closed` (the pop-up was closed first), `cancelled` (the user cancelled in the wizard\n * or in the overlay), `refused` (the wallet refused the onboarding) or `failed` (anything else in the wallet).\n * After it resolved, the overlay stays until `close()`; closing the pop-up by hand also removes it.\n */\nexport function openAsseteraOnboarding(options: OnboardingOptions): Promise<OnboardingResult> {\n const requestedWindow = options.window ?? (typeof window === \"undefined\" ? undefined : window);\n if (!requestedWindow) {\n return Promise.reject(\n new OnboardingError(\"invalid_options\", \"The Assetera Wallet onboarding can only run in a browser.\"),\n );\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const targetWindow: Window = requestedWindow;\n if (!isCaip2EvmChain(options.chain)) {\n return Promise.reject(\n new OnboardingError(\n \"invalid_options\",\n `\"${options.chain}\" is not a CAIP-2 EVM chain id (for example \"eip155:80002\").`,\n ),\n );\n }\n let walletOrigin: string;\n try {\n walletOrigin = new URL(options.walletUrl).origin;\n } catch {\n return Promise.reject(\n new OnboardingError(\"invalid_options\", `\"${options.walletUrl}\" is not a valid wallet URL.`),\n );\n }\n\n const labels = resolveLabels(options);\n const overlayEnabled = options.overlay !== false;\n\n // MUST stay synchronous, before the first await, so the pop-up runs inside the caller's user activation.\n const popup = targetWindow.open(\n onboardUrl(options.walletUrl, targetWindow.location.origin, {\n chain: options.chain,\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n ...(options.addWallet ? { add: true } : {}),\n ...(options.signIn === undefined ? {} : { signIn: options.signIn }),\n }),\n POPUP_NAME,\n options.popupFeatures ?? defaultPopupFeatures(targetWindow),\n );\n\n if (!popup) {\n // Nothing was opened, so there is nothing to wait for and no overlay: the partner page stays usable.\n return Promise.reject(new OnboardingError(\"popup_blocked\", labels.blocked));\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const activePopup: Window = popup;\n\n return new Promise<OnboardingResult>((resolve, reject) => {\n // Phase 1 waits for `onboarded`; phase 2 (after it) keeps the pop-up for signature requests until `close()`.\n let onboarded = false;\n let finished = false;\n let closeTimer: ReturnType<typeof setInterval> | null = null;\n let overlay: HTMLElement | null = null;\n const pending = new Map<\n string,\n { resolve: (signature: `0x${string}`) => void; reject: (error: OnboardingError) => void }\n >();\n\n function cleanup(): void {\n finished = true;\n targetWindow.removeEventListener(\"message\", onMessage);\n if (closeTimer !== null) {\n clearInterval(closeTimer);\n closeTimer = null;\n }\n overlay?.remove();\n overlay = null;\n }\n\n function failPending(error: OnboardingError): void {\n for (const entry of pending.values()) entry.reject(error);\n pending.clear();\n }\n\n function close(): void {\n if (finished) return;\n failPending(new OnboardingError(\"closed\", \"The Assetera Wallet window was closed.\"));\n cleanup();\n if (!activePopup.closed) activePopup.close();\n }\n\n function fail(error: OnboardingError): void {\n if (onboarded || finished) return;\n cleanup();\n reject(error);\n }\n\n function cancel(): void {\n if (onboarded) {\n close();\n return;\n }\n activePopup.close();\n fail(new OnboardingError(\"cancelled\", \"The user cancelled the Assetera Wallet onboarding.\"));\n }\n\n function signMessage(message: string): Promise<`0x${string}`> {\n if (finished || activePopup.closed) {\n return Promise.reject(new OnboardingError(\"closed\", \"The Assetera Wallet window was closed.\"));\n }\n const id = globalThis.crypto.randomUUID();\n const request: RequestMessage = {\n type: `${MESSAGE_PREFIX}request`,\n v: PROTOCOL_VERSION,\n id,\n method: \"personal_sign\",\n params: [message, address as `0x${string}`],\n };\n return new Promise((resolveSign, rejectSign) => {\n pending.set(id, { resolve: resolveSign, reject: rejectSign });\n activePopup.focus();\n activePopup.postMessage(request, walletOrigin);\n });\n }\n\n // Set with `onboarded`; `signMessage` is only handed out after that.\n let address: `0x${string}` | undefined;\n\n function onMessage(event: MessageEvent): void {\n // Trust rule: accept only the wallet origin AND the exact pop-up we opened. Ignore everything else.\n if (event.origin !== walletOrigin) return;\n if ((event.source as unknown) !== activePopup) return;\n const data: unknown = event.data;\n if (!onboarded) {\n if (isOnboardedMessage(data)) {\n onboarded = true;\n address = data.address;\n resolve({\n address: data.address,\n chain: data.chain,\n created: data.created ?? true,\n signMessage,\n close,\n });\n return;\n }\n if (isOnboardCancelledMessage(data)) {\n fail(new OnboardingError(cancelCode(data.reason), data.message ?? cancelMessage(data.reason)));\n }\n return;\n }\n if (isResponseMessage(data)) {\n const entry = pending.get(data.id);\n if (!entry) return;\n pending.delete(data.id);\n if (\"error\" in data) {\n entry.reject(\n new OnboardingError(\n data.error.code === RpcErrorCode.UserRejected ? \"cancelled\" : \"failed\",\n data.error.message,\n ),\n );\n } else if (typeof data.result === \"string\" && /^0x[0-9a-fA-F]+$/.test(data.result)) {\n entry.resolve(data.result as `0x${string}`);\n } else {\n entry.reject(new OnboardingError(\"failed\", \"The Assetera Wallet returned no signature.\"));\n }\n }\n }\n\n targetWindow.addEventListener(\"message\", onMessage);\n closeTimer = setInterval(() => {\n if (!activePopup.closed) return;\n if (onboarded) {\n close();\n return;\n }\n fail(\n new OnboardingError(\"closed\", \"The Assetera Wallet window was closed before onboarding finished.\"),\n );\n }, CLOSE_POLL_MS);\n\n if (overlayEnabled) {\n overlay = showOverlay(targetWindow, labels, {\n onFocus: () => activePopup.focus(),\n onCancel: cancel,\n });\n }\n });\n}\n","/**\n * Manage-wallet opener for the Assetera Wallet: the partner side of the `/manage` pop-up (AO-1436).\n *\n * A partner page shows a \"Manage wallet\" button. On the click this module opens the wallet pop-up on the manage\n * route synchronously (so the browser treats it as part of the click). The client sees the wallet accounts and\n * the wallet security (passkeys, authenticator app, recovery codes) and can change them. The pop-up never\n * answers `request` messages; it posts `security` messages while it is open.\n */\nimport { isSecurityMessage, manageUrl, type SignInHint, type WalletSecurityStatus } from \"./protocol\";\nimport { defaultPopupFeatures } from \"./popup\";\n\n/** Why {@link openAsseteraWalletManager} threw. */\nexport type ManagerErrorCode = \"popup_blocked\" | \"invalid_options\";\n\n/** Error thrown by {@link openAsseteraWalletManager}. `code` is stable and safe to branch on. */\nexport class ManagerError extends Error {\n readonly code: ManagerErrorCode;\n\n constructor(code: ManagerErrorCode, message: string) {\n super(message);\n this.name = \"ManagerError\";\n this.code = code;\n }\n}\n\n/** Options for {@link openAsseteraWalletManager}. */\nexport interface WalletManagerOptions {\n /** Base URL of the wallet origin, e.g. `https://wallet.wallet-staging.assetera.com`. */\n walletUrl: string;\n /** Sign-in hint passed as `signIn`, e.g. `\"assetera-marketplace\"`. Only a hint; the wallet may ignore it. */\n signIn?: SignInHint;\n /** Language passed as `lang`, e.g. `\"en\"` or `\"de\"`. */\n locale?: string;\n /** `window.open` feature string. Defaults to a centred `\"popup,width=440,height=760,left=…,top=…\"`. */\n popupFeatures?: string;\n /** Called for every `security` message from the pop-up. */\n onSecurity?: (status: WalletSecurityStatus) => void;\n /** Injectable `window` for tests; defaults to `globalThis.window`. */\n window?: Window;\n}\n\n/** The open manage pop-up, controlled by the partner. */\nexport interface WalletManager {\n /** Close the pop-up and remove the listener and the close timer. Safe to call more than once. */\n close: () => void;\n /** Resolves when the pop-up is closed, by the partner or by the client. */\n closed: Promise<void>;\n /** The last security status the pop-up sent, or `undefined` when none arrived yet. */\n lastSecurity: () => WalletSecurityStatus | undefined;\n}\n\nconst POPUP_NAME = \"assetera-wallet-manage\";\nconst CLOSE_POLL_MS = 500;\n\n/**\n * Open the manage-wallet pop-up for the Assetera Wallet and return a handle to it.\n *\n * Call this from a user click (a button handler). `window.open` runs synchronously inside the call, before any\n * `await`, so the browser allows it; when the browser blocks the pop-up this throws `ManagerError` with code\n * `popup_blocked`.\n *\n * The pop-up checks the `origin` query parameter against the wallet's partner list, posts `ready` to\n * `window.opener` and then posts `security` messages. Messages are accepted only when they come from the wallet\n * origin AND from the pop-up that was opened here. The pop-up does not answer `request` messages.\n */\nexport function openAsseteraWalletManager(options: WalletManagerOptions): WalletManager {\n const requestedWindow = options.window ?? (typeof window === \"undefined\" ? undefined : window);\n if (!requestedWindow) {\n throw new ManagerError(\"invalid_options\", \"The Assetera Wallet manager can only run in a browser.\");\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const targetWindow: Window = requestedWindow;\n let walletOrigin: string;\n try {\n walletOrigin = new URL(options.walletUrl).origin;\n } catch {\n throw new ManagerError(\"invalid_options\", `\"${options.walletUrl}\" is not a valid wallet URL.`);\n }\n\n // MUST stay synchronous, before any await, so the pop-up runs inside the caller's user activation.\n const popup = targetWindow.open(\n manageUrl(options.walletUrl, targetWindow.location.origin, {\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n ...(options.signIn === undefined ? {} : { signIn: options.signIn }),\n }),\n POPUP_NAME,\n options.popupFeatures ?? defaultPopupFeatures(targetWindow),\n );\n\n if (!popup) {\n throw new ManagerError(\n \"popup_blocked\",\n \"Your browser blocked the Assetera Wallet window. Allow pop-ups for this site and try again.\",\n );\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const activePopup: Window = popup;\n\n let finished = false;\n let lastSecurity: WalletSecurityStatus | undefined;\n let closeTimer: ReturnType<typeof setInterval> | null = null;\n let resolveClosed!: () => void;\n const closed = new Promise<void>((resolve) => {\n resolveClosed = resolve;\n });\n\n function cleanup(): void {\n if (finished) return;\n finished = true;\n targetWindow.removeEventListener(\"message\", onMessage);\n if (closeTimer !== null) {\n clearInterval(closeTimer);\n closeTimer = null;\n }\n resolveClosed();\n }\n\n function close(): void {\n cleanup();\n if (!activePopup.closed) activePopup.close();\n }\n\n function onMessage(event: MessageEvent): void {\n // Trust rule: accept only the wallet origin AND the exact pop-up we opened. Ignore everything else.\n if (event.origin !== walletOrigin) return;\n if ((event.source as unknown) !== activePopup) return;\n const data: unknown = event.data;\n if (!isSecurityMessage(data)) return;\n const status: WalletSecurityStatus = {\n protection: data.data.protection,\n passkeys: data.data.passkeys,\n authenticatorApps: data.data.authenticatorApps,\n };\n lastSecurity = status;\n options.onSecurity?.(status);\n }\n\n targetWindow.addEventListener(\"message\", onMessage);\n closeTimer = setInterval(() => {\n if (activePopup.closed) cleanup();\n }, CLOSE_POLL_MS);\n\n return {\n close,\n closed,\n lastSecurity: () => lastSecurity,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/popup.ts","../src/onboarding.ts","../src/manage.ts"],"names":["POPUP_NAME","CLOSE_POLL_MS","copyAccountNames"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Small helpers shared by the pop-up openers in this package. They are internal and are not part of the public\n * API through `index.ts`.\n */\n\n/** Default width, in pixels, of the onboarding and manage pop-ups. */\nexport const POPUP_WIDTH = 440;\n\n/** Default height, in pixels, of the onboarding and manage pop-ups. */\nexport const POPUP_HEIGHT = 760;\n\n/**\n * Build the centred `window.open` feature string for a pop-up of the default size. `win` is the opener window:\n * the pop-up is centred over it, and safe defaults are used when the browser does not expose the geometry.\n */\nexport function defaultPopupFeatures(win: Window): string {\n const screenX = Number.isFinite(win.screenX) ? win.screenX : 0;\n const screenY = Number.isFinite(win.screenY) ? win.screenY : 0;\n const outerWidth = Number.isFinite(win.outerWidth) ? win.outerWidth : POPUP_WIDTH;\n const outerHeight = Number.isFinite(win.outerHeight) ? win.outerHeight : POPUP_HEIGHT;\n const left = Math.max(0, Math.round(screenX + (outerWidth - POPUP_WIDTH) / 2));\n const top = Math.max(0, Math.round(screenY + (outerHeight - POPUP_HEIGHT) / 2));\n return `popup,width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top}`;\n}\n","/**\n * Onboarding opener for the Assetera Wallet: the partner side of the `/onboard` wizard (AO-1274).\n *\n * A tied-agent bank site shows a \"Create an Assetera wallet\" button. On the click, this module opens the wallet\n * pop-up in onboarding mode synchronously (so the browser treats it as part of the click) and waits for the\n * wizard to post the new wallet address back. While the pop-up is open the partner page shows a dimming\n * overlay; the overlay is plain DOM (no React, no CSS files) so any partner can drop this in.\n *\n * The wallet's `/onboard` page is the pop-up side and speaks the same protocol in `./protocol`, but it uses the\n * message types and the `ONBOARD_PATH` from there, so the two sides cannot drift apart.\n */\nimport {\n MESSAGE_PREFIX,\n PROTOCOL_VERSION,\n RpcErrorCode,\n isAccountsMessage,\n isCaip2EvmChain,\n isOnboardCancelledMessage,\n isOnboardedMessage,\n isResponseMessage,\n onboardUrl,\n type OnboardCancelledMessage,\n type RequestMessage,\n type SignInHint,\n type WalletAccountName,\n} from \"./protocol\";\nimport { defaultPopupFeatures } from \"./popup\";\n\n/** Why {@link openAsseteraOnboarding} rejected. */\nexport type OnboardingErrorCode =\n \"popup_blocked\" | \"closed\" | \"cancelled\" | \"refused\" | \"failed\" | \"invalid_options\";\n\n/** Error thrown (well, rejected) by {@link openAsseteraOnboarding}. `code` is stable and safe to branch on. */\nexport class OnboardingError extends Error {\n readonly code: OnboardingErrorCode;\n\n constructor(code: OnboardingErrorCode, message: string) {\n super(message);\n this.name = \"OnboardingError\";\n this.code = code;\n }\n}\n\n/**\n * The client's Assetera Wallet, with the pop-up still open.\n *\n * The wallet is NOT registered with any compliance service. A regulated partner registers it itself, like any\n * other wallet: fetch a challenge for `address`, pass it to `signMessage`, send the signature to its compliance\n * service, then call `close()`. Always call `close()`: it closes the pop-up and removes the overlay.\n */\nexport interface OnboardingResult {\n address: `0x${string}`;\n chain: string;\n /** `true` when the wallet was created in this run, `false` when the client's existing wallet was returned. */\n created: boolean;\n /**\n * Ask the client to sign `message` (EIP-191 `personal_sign`) with this wallet in the open pop-up. Rejects with\n * `OnboardingError(\"cancelled\")` when the client declines, `\"closed\"` when the pop-up is gone, else `\"failed\"`.\n */\n signMessage: (message: string) => Promise<`0x${string}`>;\n /** Close the pop-up and remove the overlay. Safe to call more than once. */\n close: () => void;\n /**\n * The last account names the pop-up sent after it reported the address, or `undefined` when none arrived yet.\n * The returned list is a copy.\n */\n lastAccounts: () => WalletAccountName[] | undefined;\n}\n\n/** Text of the dimming overlay, all optional. Any key left out keeps its English default. */\nexport interface OverlayLabels {\n title?: string;\n body?: string;\n focus?: string;\n cancel?: string;\n blocked?: string;\n}\n\n/** Options for {@link openAsseteraOnboarding}. */\nexport interface OnboardingOptions {\n /** Base URL of the wallet origin, e.g. `https://wallet.wallet-staging.assetera.com`. */\n walletUrl: string;\n /** CAIP-2 chain id the new wallet should be created on, e.g. `eip155:80002`. An invalid value rejects with `invalid_options`. */\n chain: string;\n /** Wizard language passed as `lang`, e.g. `\"en\"` or `\"de\"`. */\n locale?: string;\n /** `window.open` feature string. Defaults to a centred `\"popup,width=440,height=760,left=…,top=…\"`. */\n popupFeatures?: string;\n /** `true` (default) shows the dimming overlay, `false` hides it, an object overrides its text. */\n overlay?: boolean | OverlayLabels;\n /** Only used in the overlay text, e.g. `\"Musterbank\"`. */\n partnerName?: string;\n /** Ask for one more wallet even when the client already has one (\"Create another Assetera Wallet\"). */\n addWallet?: boolean;\n /** Sign-in hint passed as `signIn`, e.g. `\"assetera-marketplace\"`. Only a hint; the wallet may ignore it. */\n signIn?: SignInHint;\n /** Called for every `accounts` message the pop-up sends after it reported the address. */\n onAccounts?: (accounts: WalletAccountName[]) => void;\n /** Injectable `window` for tests; defaults to `globalThis.window`. */\n window?: Window;\n}\n\nconst POPUP_NAME = \"assetera-wallet-onboarding\";\nconst CLOSE_POLL_MS = 500;\nconst OVERLAY_Z_INDEX = 2147483000;\n\nconst DEFAULT_LABELS: Required<OverlayLabels> = {\n title: \"Continue in the Assetera Wallet window\",\n body: \"A secure Assetera Wallet window is open. Follow the steps there. This page continues by itself when you are done.\",\n focus: \"Show the wallet window\",\n cancel: \"Cancel\",\n blocked: \"Your browser blocked the Assetera Wallet window. Allow pop-ups for this site and try again.\",\n};\n\ninterface OverlayHandlers {\n onFocus: () => void;\n onCancel: () => void;\n}\n\nfunction resolveLabels(options: OnboardingOptions): Required<OverlayLabels> {\n const overrides: OverlayLabels =\n typeof options.overlay === \"object\" && options.overlay !== null ? options.overlay : {};\n const partnerName = options.partnerName;\n const defaultBody = partnerName\n ? `A secure Assetera Wallet window is open for ${partnerName}. Follow the steps there. This page continues by itself when you are done.`\n : DEFAULT_LABELS.body;\n return {\n title: overrides.title ?? DEFAULT_LABELS.title,\n body: overrides.body ?? defaultBody,\n focus: overrides.focus ?? DEFAULT_LABELS.focus,\n cancel: overrides.cancel ?? DEFAULT_LABELS.cancel,\n blocked: overrides.blocked ?? DEFAULT_LABELS.blocked,\n };\n}\n\nfunction cancelCode(reason: OnboardCancelledMessage[\"reason\"]): OnboardingErrorCode {\n if (reason === \"user\") return \"cancelled\";\n if (reason === \"refused\") return \"refused\";\n return \"failed\";\n}\n\nfunction cancelMessage(reason: OnboardCancelledMessage[\"reason\"]): string {\n if (reason === \"user\") return \"The user cancelled the Assetera Wallet onboarding.\";\n if (reason === \"refused\") return \"The Assetera Wallet refused the onboarding.\";\n return \"The Assetera Wallet onboarding failed.\";\n}\n\n/** A copy of a list of named accounts, so callers never get the opener's own list. */\nfunction copyAccountNames(accounts: readonly WalletAccountName[]): WalletAccountName[] {\n return accounts.map((account) => ({ address: account.address, name: account.name }));\n}\n\n/**\n * Build the dimming overlay. Text is inserted with `textContent` only and every style is inline, so the\n * overlay cannot pick up partner CSS and cannot be scripted through an injected string.\n */\nfunction showOverlay(win: Window, labels: Required<OverlayLabels>, handlers: OverlayHandlers): HTMLElement {\n const doc = win.document;\n const root = doc.createElement(\"div\");\n root.setAttribute(\"role\", \"dialog\");\n root.setAttribute(\"aria-modal\", \"true\");\n root.setAttribute(\"data-assetera-onboarding-overlay\", \"\");\n root.style.cssText = [\n \"position: fixed\",\n \"inset: 0\",\n \"display: flex\",\n \"align-items: center\",\n \"justify-content: center\",\n \"padding: 24px\",\n \"box-sizing: border-box\",\n \"background: rgba(15,20,30,0.6)\",\n `z-index: ${OVERLAY_Z_INDEX}`,\n \"font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n ].join(\"; \");\n\n const card = doc.createElement(\"div\");\n card.style.cssText = [\n \"box-sizing: border-box\",\n \"width: 100%\",\n \"max-width: 420px\",\n \"border-radius: 16px\",\n \"padding: 24px\",\n \"background: #ffffff\",\n \"color: #101828\",\n \"box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35)\",\n ].join(\"; \");\n\n const title = doc.createElement(\"h2\");\n title.textContent = labels.title;\n title.style.cssText = \"margin: 0 0 10px; font-size: 18px; line-height: 1.3; font-weight: 600;\";\n\n const body = doc.createElement(\"p\");\n body.textContent = labels.body;\n body.style.cssText = \"margin: 0 0 20px; font-size: 14px; line-height: 1.5; color: #475467;\";\n\n const focus = doc.createElement(\"button\");\n focus.type = \"button\";\n focus.textContent = labels.focus;\n focus.style.cssText = [\n \"padding: 10px 16px\",\n \"border: 0\",\n \"border-radius: 10px\",\n \"background: #101828\",\n \"color: #ffffff\",\n \"font: inherit\",\n \"font-weight: 600\",\n \"cursor: pointer\",\n ].join(\"; \");\n focus.addEventListener(\"click\", handlers.onFocus);\n\n const cancel = doc.createElement(\"button\");\n cancel.type = \"button\";\n cancel.textContent = labels.cancel;\n cancel.style.cssText = [\n \"padding: 10px 16px\",\n \"border: 0\",\n \"border-radius: 10px\",\n \"background: transparent\",\n \"color: #475467\",\n \"font: inherit\",\n \"cursor: pointer\",\n ].join(\"; \");\n cancel.addEventListener(\"click\", handlers.onCancel);\n\n const actions = doc.createElement(\"div\");\n actions.style.cssText = \"display: flex; gap: 8px; align-items: center;\";\n actions.append(focus, cancel);\n\n card.append(title, body, actions);\n root.append(card);\n doc.body.append(root);\n return root;\n}\n\n/**\n * Open the Assetera Wallet onboarding wizard in a pop-up and resolve with the client's wallet, the pop-up still\n * open so the partner can ask for the ownership signature (see {@link OnboardingResult}).\n *\n * Call this from a user click (a button handler). `window.open` runs synchronously inside the call, before any\n * `await`, so the browser allows it; if the browser blocks the pop-up the promise rejects with\n * `OnboardingError(\"popup_blocked\")` and no overlay is shown.\n *\n * The promise rejects with `OnboardingError` and one of these codes: `invalid_options` (bad chain or wallet\n * URL), `popup_blocked`, `closed` (the pop-up was closed first), `cancelled` (the user cancelled in the wizard\n * or in the overlay), `refused` (the wallet refused the onboarding) or `failed` (anything else in the wallet).\n * After it resolved, the overlay stays until `close()`; closing the pop-up by hand also removes it. After it\n * reported the address the pop-up may send `accounts` messages; `onAccounts` receives each list and\n * `lastAccounts()` returns the last one.\n */\nexport function openAsseteraOnboarding(options: OnboardingOptions): Promise<OnboardingResult> {\n const requestedWindow = options.window ?? (typeof window === \"undefined\" ? undefined : window);\n if (!requestedWindow) {\n return Promise.reject(\n new OnboardingError(\"invalid_options\", \"The Assetera Wallet onboarding can only run in a browser.\"),\n );\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const targetWindow: Window = requestedWindow;\n if (!isCaip2EvmChain(options.chain)) {\n return Promise.reject(\n new OnboardingError(\n \"invalid_options\",\n `\"${options.chain}\" is not a CAIP-2 EVM chain id (for example \"eip155:80002\").`,\n ),\n );\n }\n let walletOrigin: string;\n try {\n walletOrigin = new URL(options.walletUrl).origin;\n } catch {\n return Promise.reject(\n new OnboardingError(\"invalid_options\", `\"${options.walletUrl}\" is not a valid wallet URL.`),\n );\n }\n\n const labels = resolveLabels(options);\n const overlayEnabled = options.overlay !== false;\n\n // MUST stay synchronous, before the first await, so the pop-up runs inside the caller's user activation.\n const popup = targetWindow.open(\n onboardUrl(options.walletUrl, targetWindow.location.origin, {\n chain: options.chain,\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n ...(options.addWallet ? { add: true } : {}),\n ...(options.signIn === undefined ? {} : { signIn: options.signIn }),\n }),\n POPUP_NAME,\n options.popupFeatures ?? defaultPopupFeatures(targetWindow),\n );\n\n if (!popup) {\n // Nothing was opened, so there is nothing to wait for and no overlay: the partner page stays usable.\n return Promise.reject(new OnboardingError(\"popup_blocked\", labels.blocked));\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const activePopup: Window = popup;\n\n return new Promise<OnboardingResult>((resolve, reject) => {\n // Phase 1 waits for `onboarded`; phase 2 (after it) keeps the pop-up for signature requests until `close()`.\n let onboarded = false;\n let finished = false;\n let closeTimer: ReturnType<typeof setInterval> | null = null;\n let overlay: HTMLElement | null = null;\n const pending = new Map<\n string,\n { resolve: (signature: `0x${string}`) => void; reject: (error: OnboardingError) => void }\n >();\n\n function cleanup(): void {\n finished = true;\n targetWindow.removeEventListener(\"message\", onMessage);\n if (closeTimer !== null) {\n clearInterval(closeTimer);\n closeTimer = null;\n }\n overlay?.remove();\n overlay = null;\n }\n\n function failPending(error: OnboardingError): void {\n for (const entry of pending.values()) entry.reject(error);\n pending.clear();\n }\n\n function close(): void {\n if (finished) return;\n failPending(new OnboardingError(\"closed\", \"The Assetera Wallet window was closed.\"));\n cleanup();\n if (!activePopup.closed) activePopup.close();\n }\n\n function fail(error: OnboardingError): void {\n if (onboarded || finished) return;\n cleanup();\n reject(error);\n }\n\n function cancel(): void {\n if (onboarded) {\n close();\n return;\n }\n activePopup.close();\n fail(new OnboardingError(\"cancelled\", \"The user cancelled the Assetera Wallet onboarding.\"));\n }\n\n function signMessage(message: string): Promise<`0x${string}`> {\n if (finished || activePopup.closed) {\n return Promise.reject(new OnboardingError(\"closed\", \"The Assetera Wallet window was closed.\"));\n }\n const id = globalThis.crypto.randomUUID();\n const request: RequestMessage = {\n type: `${MESSAGE_PREFIX}request`,\n v: PROTOCOL_VERSION,\n id,\n method: \"personal_sign\",\n params: [message, address as `0x${string}`],\n };\n return new Promise((resolveSign, rejectSign) => {\n pending.set(id, { resolve: resolveSign, reject: rejectSign });\n activePopup.focus();\n activePopup.postMessage(request, walletOrigin);\n });\n }\n\n // Set with `onboarded`; `signMessage` is only handed out after that.\n let address: `0x${string}` | undefined;\n /** The last account names the pop-up sent after `onboarded`; kept until `close()`. */\n let lastAccountNameList: WalletAccountName[] | undefined;\n\n function onMessage(event: MessageEvent): void {\n // Trust rule: accept only the wallet origin AND the exact pop-up we opened. Ignore everything else.\n if (event.origin !== walletOrigin) return;\n if ((event.source as unknown) !== activePopup) return;\n const data: unknown = event.data;\n if (!onboarded) {\n if (isOnboardedMessage(data)) {\n onboarded = true;\n address = data.address;\n resolve({\n address: data.address,\n chain: data.chain,\n created: data.created ?? true,\n signMessage,\n close,\n lastAccounts: () =>\n lastAccountNameList === undefined ? undefined : copyAccountNames(lastAccountNameList),\n });\n return;\n }\n if (isOnboardCancelledMessage(data)) {\n fail(new OnboardingError(cancelCode(data.reason), data.message ?? cancelMessage(data.reason)));\n }\n return;\n }\n if (isAccountsMessage(data)) {\n lastAccountNameList = copyAccountNames(data.data);\n options.onAccounts?.(copyAccountNames(lastAccountNameList));\n return;\n }\n if (isResponseMessage(data)) {\n const entry = pending.get(data.id);\n if (!entry) return;\n pending.delete(data.id);\n if (\"error\" in data) {\n entry.reject(\n new OnboardingError(\n data.error.code === RpcErrorCode.UserRejected ? \"cancelled\" : \"failed\",\n data.error.message,\n ),\n );\n } else if (typeof data.result === \"string\" && /^0x[0-9a-fA-F]+$/.test(data.result)) {\n entry.resolve(data.result as `0x${string}`);\n } else {\n entry.reject(new OnboardingError(\"failed\", \"The Assetera Wallet returned no signature.\"));\n }\n }\n }\n\n targetWindow.addEventListener(\"message\", onMessage);\n closeTimer = setInterval(() => {\n if (!activePopup.closed) return;\n if (onboarded) {\n close();\n return;\n }\n fail(\n new OnboardingError(\"closed\", \"The Assetera Wallet window was closed before onboarding finished.\"),\n );\n }, CLOSE_POLL_MS);\n\n if (overlayEnabled) {\n overlay = showOverlay(targetWindow, labels, {\n onFocus: () => activePopup.focus(),\n onCancel: cancel,\n });\n }\n });\n}\n","/**\n * Manage-wallet opener for the Assetera Wallet: the partner side of the `/manage` pop-up (AO-1436).\n *\n * A partner page shows a \"Manage wallet\" button. On the click this module opens the wallet pop-up on the manage\n * route synchronously (so the browser treats it as part of the click). The client sees the wallet accounts and\n * the wallet security (passkeys, authenticator app, recovery codes) and can change them. The pop-up never\n * answers `request` messages; it posts `security` and `accounts` messages while it is open.\n */\nimport {\n isAccountsMessage,\n isSecurityMessage,\n manageUrl,\n type SignInHint,\n type WalletAccountName,\n type WalletSecurityStatus,\n} from \"./protocol\";\nimport { defaultPopupFeatures } from \"./popup\";\n\n/** Why {@link openAsseteraWalletManager} threw. */\nexport type ManagerErrorCode = \"popup_blocked\" | \"invalid_options\";\n\n/** Error thrown by {@link openAsseteraWalletManager}. `code` is stable and safe to branch on. */\nexport class ManagerError extends Error {\n readonly code: ManagerErrorCode;\n\n constructor(code: ManagerErrorCode, message: string) {\n super(message);\n this.name = \"ManagerError\";\n this.code = code;\n }\n}\n\n/** Options for {@link openAsseteraWalletManager}. */\nexport interface WalletManagerOptions {\n /** Base URL of the wallet origin, e.g. `https://wallet.wallet-staging.assetera.com`. */\n walletUrl: string;\n /** Sign-in hint passed as `signIn`, e.g. `\"assetera-marketplace\"`. Only a hint; the wallet may ignore it. */\n signIn?: SignInHint;\n /** Language passed as `lang`, e.g. `\"en\"` or `\"de\"`. */\n locale?: string;\n /** `window.open` feature string. Defaults to a centred `\"popup,width=440,height=760,left=…,top=…\"`. */\n popupFeatures?: string;\n /** Called for every `security` message from the pop-up. */\n onSecurity?: (status: WalletSecurityStatus) => void;\n /** Called for every `accounts` message from the pop-up. */\n onAccounts?: (accounts: WalletAccountName[]) => void;\n /** Injectable `window` for tests; defaults to `globalThis.window`. */\n window?: Window;\n}\n\n/** The open manage pop-up, controlled by the partner. */\nexport interface WalletManager {\n /** Close the pop-up and remove the listener and the close timer. Safe to call more than once. */\n close: () => void;\n /** Resolves when the pop-up is closed, by the partner or by the client. */\n closed: Promise<void>;\n /** The last security status the pop-up sent, or `undefined` when none arrived yet. */\n lastSecurity: () => WalletSecurityStatus | undefined;\n /** The last account names the pop-up sent, or `undefined` when none arrived yet. */\n lastAccounts: () => WalletAccountName[] | undefined;\n}\n\nconst POPUP_NAME = \"assetera-wallet-manage\";\nconst CLOSE_POLL_MS = 500;\n\n/**\n * Open the manage-wallet pop-up for the Assetera Wallet and return a handle to it.\n *\n * Call this from a user click (a button handler). `window.open` runs synchronously inside the call, before any\n * `await`, so the browser allows it; when the browser blocks the pop-up this throws `ManagerError` with code\n * `popup_blocked`.\n *\n * The pop-up checks the `origin` query parameter against the wallet's partner list, posts `ready` to\n * `window.opener` and then posts `security` and `accounts` messages. Messages are accepted only when they come\n * from the wallet origin AND from the pop-up that was opened here. The pop-up does not answer `request`\n * messages.\n */\nexport function openAsseteraWalletManager(options: WalletManagerOptions): WalletManager {\n const requestedWindow = options.window ?? (typeof window === \"undefined\" ? undefined : window);\n if (!requestedWindow) {\n throw new ManagerError(\"invalid_options\", \"The Assetera Wallet manager can only run in a browser.\");\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const targetWindow: Window = requestedWindow;\n let walletOrigin: string;\n try {\n walletOrigin = new URL(options.walletUrl).origin;\n } catch {\n throw new ManagerError(\"invalid_options\", `\"${options.walletUrl}\" is not a valid wallet URL.`);\n }\n\n // MUST stay synchronous, before any await, so the pop-up runs inside the caller's user activation.\n const popup = targetWindow.open(\n manageUrl(options.walletUrl, targetWindow.location.origin, {\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n ...(options.signIn === undefined ? {} : { signIn: options.signIn }),\n }),\n POPUP_NAME,\n options.popupFeatures ?? defaultPopupFeatures(targetWindow),\n );\n\n if (!popup) {\n throw new ManagerError(\n \"popup_blocked\",\n \"Your browser blocked the Assetera Wallet window. Allow pop-ups for this site and try again.\",\n );\n }\n // A non-optional alias so TypeScript keeps the narrowed type inside the callbacks below.\n const activePopup: Window = popup;\n\n let finished = false;\n let lastSecurity: WalletSecurityStatus | undefined;\n let lastAccounts: WalletAccountName[] | undefined;\n let closeTimer: ReturnType<typeof setInterval> | null = null;\n let resolveClosed!: () => void;\n const closed = new Promise<void>((resolve) => {\n resolveClosed = resolve;\n });\n\n function cleanup(): void {\n if (finished) return;\n finished = true;\n targetWindow.removeEventListener(\"message\", onMessage);\n if (closeTimer !== null) {\n clearInterval(closeTimer);\n closeTimer = null;\n }\n resolveClosed();\n }\n\n function close(): void {\n cleanup();\n if (!activePopup.closed) activePopup.close();\n }\n\n /** A copy of a list of named accounts, so callers never get the manager's own list. */\n function copyAccountNames(accounts: readonly WalletAccountName[]): WalletAccountName[] {\n return accounts.map((account) => ({ address: account.address, name: account.name }));\n }\n\n function onMessage(event: MessageEvent): void {\n // Trust rule: accept only the wallet origin AND the exact pop-up we opened. Ignore everything else.\n if (event.origin !== walletOrigin) return;\n if ((event.source as unknown) !== activePopup) return;\n const data: unknown = event.data;\n if (isSecurityMessage(data)) {\n const status: WalletSecurityStatus = {\n protection: data.data.protection,\n passkeys: data.data.passkeys,\n authenticatorApps: data.data.authenticatorApps,\n };\n lastSecurity = status;\n options.onSecurity?.(status);\n return;\n }\n if (isAccountsMessage(data)) {\n lastAccounts = copyAccountNames(data.data);\n options.onAccounts?.(copyAccountNames(lastAccounts));\n }\n }\n\n targetWindow.addEventListener(\"message\", onMessage);\n closeTimer = setInterval(() => {\n if (activePopup.closed) cleanup();\n }, CLOSE_POLL_MS);\n\n return {\n close,\n closed,\n lastSecurity: () => lastSecurity,\n lastAccounts: () => (lastAccounts === undefined ? undefined : copyAccountNames(lastAccounts)),\n };\n}\n"]}
package/dist/protocol.cjs CHANGED
@@ -68,6 +68,27 @@ function isSecurityMessage(value) {
68
68
  const data = value.data;
69
69
  return isRecord(data) && typeof data.protection === "string" && WALLET_PROTECTIONS.includes(data.protection) && isCount(data.passkeys) && isCount(data.authenticatorApps);
70
70
  }
71
+ var MAX_ACCOUNT_NAMES = 50;
72
+ function hasControlCharacter(value) {
73
+ for (const character of value) {
74
+ const code = character.codePointAt(0) ?? 0;
75
+ if (code <= 31 || code >= 127 && code <= 159) return true;
76
+ }
77
+ return false;
78
+ }
79
+ function isAccountName(value) {
80
+ if (typeof value !== "string") return false;
81
+ if (hasControlCharacter(value)) return false;
82
+ const trimmed = value.trim();
83
+ return trimmed.length >= 1 && trimmed.length <= 64;
84
+ }
85
+ function isAccountsMessage(value) {
86
+ if (!hasType(value, "accounts")) return false;
87
+ const data = value.data;
88
+ return Array.isArray(data) && data.length <= MAX_ACCOUNT_NAMES && data.every(
89
+ (entry) => isRecord(entry) && typeof entry.address === "string" && EVM_ADDRESS_RE.test(entry.address) && isAccountName(entry.name)
90
+ );
91
+ }
71
92
  function isRequestMessage(value) {
72
93
  return hasType(value, "request") && typeof value.id === "string" && typeof value.method === "string";
73
94
  }
@@ -120,6 +141,7 @@ exports.RpcErrorCode = RpcErrorCode;
120
141
  exports.SIGN_IN_HINTS = SIGN_IN_HINTS;
121
142
  exports.SUPPORTED_METHODS = SUPPORTED_METHODS;
122
143
  exports.connectUrl = connectUrl;
144
+ exports.isAccountsMessage = isAccountsMessage;
123
145
  exports.isCaip2EvmChain = isCaip2EvmChain;
124
146
  exports.isDisconnectMessage = isDisconnectMessage;
125
147
  exports.isEventMessage = isEventMessage;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/protocol.ts"],"names":[],"mappings":"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","file":"protocol.cjs","sourcesContent":["/**\n * The pop-up protocol between a partner page (the opener) and the Assetera Wallet (the pop-up) — ADR-0054 D3/D4.\n *\n * This file is the CONTRACT. The connector in this package speaks the opener side; AsseteraWalletFront's\n * `/connect` page speaks the pop-up side and imports these types from `@asseteragmbh/wallet-connector/protocol`.\n * Change it only in a backwards-compatible way, or bump `PROTOCOL_VERSION` and support both on the wallet side:\n * partner sites upgrade on their own schedule.\n *\n * ## The handshake\n *\n * 1. The partner opens `${walletUrl}${CONNECT_PATH}?origin=<partner origin>&v=<version>` from a user click.\n * 2. The pop-up checks the claimed origin against its allowlist (D4). If listed, it posts `ready` to\n * `window.opener` with `targetOrigin` = that origin. The browser delivers it ONLY if the opener really is\n * that origin, so a page cannot claim someone else's origin and still hear the answer.\n * 3. The opener waits for `ready` from the wallet origin, then sends `request`s with `targetOrigin` = the wallet\n * origin. The pop-up accepts a message only when `event.origin` is the allowed origin from step 2 AND\n * `event.source === window.opener`, and answers with `targetOrigin` = that origin. Nothing else is accepted.\n *\n * ## Sign-in hint\n *\n * A partner may tell the wallet how the client signed in at the partner, through the optional `signIn` URL\n * parameter (`SIGN_IN_HINTS`). The hint only names an identity provider: the wallet checks it against its own\n * list, may ignore it and then falls back to its own login page. The hint never carries a token, an identity or\n * any other credential.\n *\n * ## Lifetime\n *\n * The pop-up is not guaranteed to stay open. The wallet site may close the `/connect` pop-up after it connected\n * or answered a request. The provider keeps the last `accounts` and `chainId` it saw, so the partner page still\n * looks connected after the pop-up closes, and it opens the pop-up again on the next request from a user click.\n * (ADR-0054, \"the wallet tab must stay open\", no longer holds.)\n *\n * ## Onboarding\n *\n * Onboarding is a second flow on the same wallet origin, for a partner that wants the client to get an Assetera\n * Wallet (a new one, or the one the client already has). The partner opens\n * `${walletUrl}${ONBOARD_PATH}?origin=<partner origin>&v=<version>&chain=<CAIP-2 chain id>[&add=1]` from a user\n * click. The pop-up checks the claimed origin against its partner list, signs the client in through SSO, runs the\n * wizard (accept the wallet terms, create the wallet) and then posts `onboarded` (or `onboard-cancelled`) to\n * `window.opener` with `targetOrigin` = the partner origin. `add=1` asks for one more wallet even when the client\n * already has one.\n *\n * After `onboarded` the pop-up STAYS OPEN and answers `request` messages for `personal_sign` by the onboarded\n * address (plus `eth_accounts` and `eth_chainId`), with the same `response` messages as `/connect`. That is how\n * the partner gets the ownership signature it needs to register the wallet with its own compliance service: the\n * wallet itself never calls a regulated service (ADR-0059 D3), and a second `window.open` after an asynchronous\n * step would be blocked by the browser. The partner closes the pop-up when it is done.\n *\n * The opener accepts messages only when `event.origin` is the wallet origin AND `event.source` is the pop-up\n * it opened. The wizard never returns a private key or a token, only the wallet address and signatures the\n * client approved.\n *\n * ## Manage\n *\n * The partner can open `${walletUrl}${MANAGE_PATH}?origin=<partner origin>&v=<version>[&lang=<locale>][&signIn=<hint>]`\n * from a user click, so the client can see and change the wallet accounts and the wallet security (passkeys,\n * authenticator app, recovery codes). The pop-up checks the claimed origin against its partner list, posts\n * `ready` to `window.opener` (the same message as `/connect`) and then posts `security` messages. It never\n * answers `request` messages.\n */\n\nexport const PROTOCOL_VERSION = 1 as const;\n\n/** The pop-up route on the wallet origin. */\nexport const CONNECT_PATH = \"/connect\";\n\n/** The onboarding wizard route on the wallet origin. */\nexport const ONBOARD_PATH = \"/onboard\";\n\n/** The manage wallet route on the wallet origin. */\nexport const MANAGE_PATH = \"/manage\";\n\n/** The identity providers a partner can name in the `signIn` hint. */\nexport const SIGN_IN_HINTS = [\"assetera-marketplace\"] as const;\n\n/** A named identity provider the wallet may use for a silent sign-in. */\nexport type SignInHint = (typeof SIGN_IN_HINTS)[number];\n\n/** True when `value` is one of {@link SIGN_IN_HINTS}. */\nexport function isSignInHint(value: unknown): value is SignInHint {\n return (SIGN_IN_HINTS as readonly unknown[]).includes(value);\n}\n\n/** Every message carries this prefix in `type`, so both sides can ignore unrelated `postMessage` traffic. */\nexport const MESSAGE_PREFIX = \"assetera-wallet:\" as const;\n\n/**\n * The EIP-1193 methods the pop-up answers (ADR-0054 D3). Anything else is refused with 4200. Read-only chain\n * calls (`eth_call`, `eth_getBalance`, …) do not go through the pop-up; wagmi sends them to its own transports.\n */\nexport const SUPPORTED_METHODS = [\n \"eth_requestAccounts\",\n \"eth_accounts\",\n \"eth_chainId\",\n \"wallet_switchEthereumChain\",\n \"personal_sign\",\n \"eth_signTypedData_v4\",\n \"eth_sendTransaction\",\n] as const;\n\nexport type SupportedMethod = (typeof SUPPORTED_METHODS)[number];\n\nexport function isSupportedMethod(method: string): method is SupportedMethod {\n return (SUPPORTED_METHODS as readonly string[]).includes(method);\n}\n\n/** EIP-1193 / EIP-1474 error codes the pop-up uses. */\nexport const RpcErrorCode = {\n /** The client rejected the request in the pop-up. */\n UserRejected: 4001,\n /** Not connected yet (no `eth_requestAccounts` approved in this pop-up). */\n Unauthorized: 4100,\n /** The method is not in SUPPORTED_METHODS. */\n UnsupportedMethod: 4200,\n /** The pop-up closed, or the wallet session ended. */\n Disconnected: 4900,\n /** `wallet_switchEthereumChain` to a chain the wallet does not offer. */\n UnrecognizedChain: 4902,\n /** Malformed params. */\n InvalidParams: -32602,\n /** Anything unexpected inside the wallet. */\n Internal: -32603,\n} as const;\n\nexport type RpcErrorCode = (typeof RpcErrorCode)[keyof typeof RpcErrorCode];\n\nexport interface RpcError {\n code: number;\n message: string;\n data?: unknown;\n}\n\n// --- pop-up → opener ---------------------------------------------------------------------------------\n\n/** The pop-up is loaded and accepts requests from this opener. */\nexport interface ReadyMessage {\n type: `${typeof MESSAGE_PREFIX}ready`;\n v: typeof PROTOCOL_VERSION;\n /** Shown to the partner for diagnostics only; the partner must not rely on it for anything. */\n walletVersion?: string;\n}\n\n/** The answer to one `request`, matched by `id`. Exactly one of `result` / `error`. */\nexport type ResponseMessage =\n | { type: `${typeof MESSAGE_PREFIX}response`; v: typeof PROTOCOL_VERSION; id: string; result: unknown }\n | { type: `${typeof MESSAGE_PREFIX}response`; v: typeof PROTOCOL_VERSION; id: string; error: RpcError };\n\n/** EIP-1193 provider events, forwarded to the partner. */\nexport type EventMessage =\n | {\n type: `${typeof MESSAGE_PREFIX}event`;\n v: typeof PROTOCOL_VERSION;\n event: \"accountsChanged\";\n data: `0x${string}`[];\n }\n | {\n type: `${typeof MESSAGE_PREFIX}event`;\n v: typeof PROTOCOL_VERSION;\n event: \"chainChanged\";\n data: `0x${string}`;\n }\n | {\n type: `${typeof MESSAGE_PREFIX}event`;\n v: typeof PROTOCOL_VERSION;\n event: \"disconnect\";\n data: RpcError;\n };\n\n/**\n * How well the client's Assetera Wallet is protected. The values are the ones the wallet site shows:\n *\n * - `add-factor`: there is no passkey and no authenticator app yet.\n * - `save-codes`: recovery codes exist, but the client has not confirmed saving them.\n * - `create-codes`: a factor exists, but there are no recovery codes.\n * - `protected`: a factor exists and the recovery codes are saved.\n * - `unknown`: the wallet could not read the state.\n */\nexport type WalletProtection = \"unknown\" | \"add-factor\" | \"save-codes\" | \"create-codes\" | \"protected\";\n\n/** The wallet security status sent by a manage (or connect) pop-up. */\nexport interface WalletSecurityStatus {\n /** Overall result, the same values the wallet site shows. */\n protection: WalletProtection;\n /** Passkeys registered for signing (Dynamic step-up), not sign-in factors. */\n passkeys: number;\n /** Authenticator apps (TOTP) registered for signing (Dynamic step-up). */\n authenticatorApps: number;\n}\n\n/**\n * The wallet reports the security status while a pop-up is open. The partner cannot ask for it. It never\n * carries a token, an identity or a credential.\n */\nexport interface SecurityMessage {\n type: `${typeof MESSAGE_PREFIX}security`;\n v: typeof PROTOCOL_VERSION;\n data: WalletSecurityStatus;\n}\n\n/**\n * The onboarding wizard finished: the client accepted the wallet terms and has an Assetera Wallet on `chain`.\n * `created` is `true` when the wallet was created in this run, `false` when the wizard returned the client's\n * existing wallet. The wallet is not registered with any compliance service; that is the partner's step.\n */\nexport interface OnboardedMessage {\n type: `${typeof MESSAGE_PREFIX}onboarded`;\n v: typeof PROTOCOL_VERSION;\n address: `0x${string}`;\n chain: string;\n created: boolean;\n /**\n * @deprecated Sent by wallet versions that registered the wallet themselves (before ADR-0059). Ignored.\n */\n status?: \"approved\" | \"pending\";\n}\n\n/** The onboarding wizard did not produce a wallet. `message` is optional diagnostics for the partner. */\nexport interface OnboardCancelledMessage {\n type: `${typeof MESSAGE_PREFIX}onboard-cancelled`;\n v: typeof PROTOCOL_VERSION;\n reason: \"user\" | \"refused\" | \"error\";\n message?: string;\n}\n\nexport type WalletToPartnerMessage =\n | ReadyMessage\n | ResponseMessage\n | EventMessage\n | SecurityMessage\n | OnboardedMessage\n | OnboardCancelledMessage;\n\n// --- opener → pop-up ---------------------------------------------------------------------------------\n\nexport interface RequestMessage {\n type: `${typeof MESSAGE_PREFIX}request`;\n v: typeof PROTOCOL_VERSION;\n /** Unique per request within one connection; the response carries it back. */\n id: string;\n method: string;\n params?: unknown[] | Record<string, unknown>;\n}\n\n/** The partner disconnects (for example the user clicked \"Disconnect\" in the partner page). */\nexport interface DisconnectMessage {\n type: `${typeof MESSAGE_PREFIX}disconnect`;\n v: typeof PROTOCOL_VERSION;\n}\n\nexport type PartnerToWalletMessage = RequestMessage | DisconnectMessage;\n\n// --- guards ------------------------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction hasType(value: unknown, suffix: string): value is Record<string, unknown> {\n return isRecord(value) && value.type === `${MESSAGE_PREFIX}${suffix}` && value.v === PROTOCOL_VERSION;\n}\n\nexport function isReadyMessage(value: unknown): value is ReadyMessage {\n return hasType(value, \"ready\");\n}\n\nexport function isResponseMessage(value: unknown): value is ResponseMessage {\n return (\n hasType(value, \"response\") &&\n typeof value.id === \"string\" &&\n (\"result\" in value || (isRecord(value.error) && typeof value.error.code === \"number\"))\n );\n}\n\nexport function isEventMessage(value: unknown): value is EventMessage {\n return (\n hasType(value, \"event\") &&\n (value.event === \"accountsChanged\" || value.event === \"chainChanged\" || value.event === \"disconnect\")\n );\n}\n\nconst WALLET_PROTECTIONS: readonly WalletProtection[] = [\n \"unknown\",\n \"add-factor\",\n \"save-codes\",\n \"create-codes\",\n \"protected\",\n];\n\n/** A factor count: a whole number, zero or more. */\nfunction isCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\n/** True for a `security` message with a known `protection` value and whole, non-negative factor counts. */\nexport function isSecurityMessage(value: unknown): value is SecurityMessage {\n if (!hasType(value, \"security\")) return false;\n const data = value.data;\n return (\n isRecord(data) &&\n typeof data.protection === \"string\" &&\n (WALLET_PROTECTIONS as readonly string[]).includes(data.protection) &&\n isCount(data.passkeys) &&\n isCount(data.authenticatorApps)\n );\n}\n\nexport function isRequestMessage(value: unknown): value is RequestMessage {\n return hasType(value, \"request\") && typeof value.id === \"string\" && typeof value.method === \"string\";\n}\n\nexport function isDisconnectMessage(value: unknown): value is DisconnectMessage {\n return hasType(value, \"disconnect\");\n}\n\n/** `0x` followed by exactly 40 hexadecimal digits, the shape of an EVM address. */\nconst EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\n\nexport function isOnboardedMessage(value: unknown): value is OnboardedMessage {\n return (\n hasType(value, \"onboarded\") &&\n typeof value.address === \"string\" &&\n EVM_ADDRESS_RE.test(value.address) &&\n typeof value.chain === \"string\" &&\n // `created` is new; an older wallet sent `status` instead and always created or reused a wallet.\n (typeof value.created === \"boolean\" || value.status === \"approved\" || value.status === \"pending\")\n );\n}\n\nexport function isOnboardCancelledMessage(value: unknown): value is OnboardCancelledMessage {\n return (\n hasType(value, \"onboard-cancelled\") &&\n (value.reason === \"user\" || value.reason === \"refused\" || value.reason === \"error\")\n );\n}\n\n/** A CAIP-2 EVM chain id, for example `eip155:80002` (Polygon Amoy) or `eip155:1` (mainnet). */\nexport function isCaip2EvmChain(value: string): boolean {\n return /^eip155:\\d{1,32}$/.test(value);\n}\n\n/**\n * The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. `signIn` adds the\n * optional sign-in hint; it is only a hint and the wallet may ignore it.\n */\nexport function connectUrl(walletUrl: string, partnerOrigin: string, signIn?: SignInHint): string {\n const url = new URL(CONNECT_PATH, walletUrl);\n url.searchParams.set(\"origin\", partnerOrigin);\n url.searchParams.set(\"v\", String(PROTOCOL_VERSION));\n if (signIn !== undefined) url.searchParams.set(\"signIn\", signIn);\n return url.toString();\n}\n\n/**\n * The URL the partner opens for the onboarding wizard. `partnerOrigin` is `window.location.origin` of the\n * partner page; `chain` is the CAIP-2 chain id the new wallet should be created on; `locale` is passed as `lang`\n * when the partner wants a specific wizard language. `signIn` adds the optional sign-in hint; it is only a hint\n * and the wallet may ignore it.\n */\nexport function onboardUrl(\n walletUrl: string,\n partnerOrigin: string,\n options: { chain: string; locale?: string; add?: boolean; signIn?: SignInHint },\n): string {\n const url = new URL(ONBOARD_PATH, walletUrl);\n url.searchParams.set(\"origin\", partnerOrigin);\n url.searchParams.set(\"v\", String(PROTOCOL_VERSION));\n url.searchParams.set(\"chain\", options.chain);\n if (options.locale !== undefined) url.searchParams.set(\"lang\", options.locale);\n if (options.add) url.searchParams.set(\"add\", \"1\");\n if (options.signIn !== undefined) url.searchParams.set(\"signIn\", options.signIn);\n return url.toString();\n}\n\n/**\n * The URL the partner opens to manage the wallet. `partnerOrigin` is `window.location.origin` of the partner\n * page. `locale` is passed as `lang` when the partner wants a specific language. `signIn` adds the optional\n * sign-in hint; it is only a hint and the wallet may ignore it.\n */\nexport function manageUrl(\n walletUrl: string,\n partnerOrigin: string,\n options: { locale?: string; signIn?: SignInHint } = {},\n): string {\n const url = new URL(MANAGE_PATH, walletUrl);\n url.searchParams.set(\"origin\", partnerOrigin);\n url.searchParams.set(\"v\", String(PROTOCOL_VERSION));\n if (options.locale !== undefined) url.searchParams.set(\"lang\", options.locale);\n if (options.signIn !== undefined) url.searchParams.set(\"signIn\", options.signIn);\n return url.toString();\n}\n"]}
1
+ {"version":3,"sources":["../src/protocol.ts"],"names":[],"mappings":"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","file":"protocol.cjs","sourcesContent":["/**\n * The pop-up protocol between a partner page (the opener) and the Assetera Wallet (the pop-up) — ADR-0054 D3/D4.\n *\n * This file is the CONTRACT. The connector in this package speaks the opener side; AsseteraWalletFront's\n * `/connect` page speaks the pop-up side and imports these types from `@asseteragmbh/wallet-connector/protocol`.\n * Change it only in a backwards-compatible way, or bump `PROTOCOL_VERSION` and support both on the wallet side:\n * partner sites upgrade on their own schedule.\n *\n * ## The handshake\n *\n * 1. The partner opens `${walletUrl}${CONNECT_PATH}?origin=<partner origin>&v=<version>` from a user click.\n * 2. The pop-up checks the claimed origin against its allowlist (D4). If listed, it posts `ready` to\n * `window.opener` with `targetOrigin` = that origin. The browser delivers it ONLY if the opener really is\n * that origin, so a page cannot claim someone else's origin and still hear the answer.\n * 3. The opener waits for `ready` from the wallet origin, then sends `request`s with `targetOrigin` = the wallet\n * origin. The pop-up accepts a message only when `event.origin` is the allowed origin from step 2 AND\n * `event.source === window.opener`, and answers with `targetOrigin` = that origin. Nothing else is accepted.\n *\n * ## Sign-in hint\n *\n * A partner may tell the wallet how the client signed in at the partner, through the optional `signIn` URL\n * parameter (`SIGN_IN_HINTS`). The hint only names an identity provider: the wallet checks it against its own\n * list, may ignore it and then falls back to its own login page. The hint never carries a token, an identity or\n * any other credential.\n *\n * ## Lifetime\n *\n * The pop-up is not guaranteed to stay open. The wallet site may close the `/connect` pop-up after it connected\n * or answered a request. The provider keeps the last `accounts` and `chainId` it saw, so the partner page still\n * looks connected after the pop-up closes, and it opens the pop-up again on the next request from a user click.\n * (ADR-0054, \"the wallet tab must stay open\", no longer holds.)\n *\n * ## Onboarding\n *\n * Onboarding is a second flow on the same wallet origin, for a partner that wants the client to get an Assetera\n * Wallet (a new one, or the one the client already has). The partner opens\n * `${walletUrl}${ONBOARD_PATH}?origin=<partner origin>&v=<version>&chain=<CAIP-2 chain id>[&add=1]` from a user\n * click. The pop-up checks the claimed origin against its partner list, signs the client in through SSO, runs the\n * wizard (accept the wallet terms, create the wallet) and then posts `onboarded` (or `onboard-cancelled`) to\n * `window.opener` with `targetOrigin` = the partner origin. `add=1` asks for one more wallet even when the client\n * already has one.\n *\n * After `onboarded` the pop-up STAYS OPEN and answers `request` messages for `personal_sign` by the onboarded\n * address (plus `eth_accounts` and `eth_chainId`), with the same `response` messages as `/connect`. That is how\n * the partner gets the ownership signature it needs to register the wallet with its own compliance service: the\n * wallet itself never calls a regulated service (ADR-0059 D3), and a second `window.open` after an asynchronous\n * step would be blocked by the browser. The partner closes the pop-up when it is done.\n *\n * The opener accepts messages only when `event.origin` is the wallet origin AND `event.source` is the pop-up\n * it opened. The wizard never returns a private key or a token, only the wallet address and signatures the\n * client approved.\n *\n * ## Manage\n *\n * The partner can open `${walletUrl}${MANAGE_PATH}?origin=<partner origin>&v=<version>[&lang=<locale>][&signIn=<hint>]`\n * from a user click, so the client can see and change the wallet accounts and the wallet security (passkeys,\n * authenticator app, recovery codes). The pop-up checks the claimed origin against its partner list, posts\n * `ready` to `window.opener` (the same message as `/connect`) and then posts `security` messages. It never\n * answers `request` messages.\n *\n * ## Account names\n *\n * While a pop-up is open it may also post `accounts` messages. Each entry names one account the client has\n * already shared with THIS partner, so the partner can show a name next to the address. The wallet never sends\n * an account the partner does not already know. A manage pop-up may send the message, and an onboarding pop-up\n * may send it after it reported the address. The message is only sent while a pop-up is open, never on request\n * of the partner. It carries no token and no other data.\n */\n\nexport const PROTOCOL_VERSION = 1 as const;\n\n/** The pop-up route on the wallet origin. */\nexport const CONNECT_PATH = \"/connect\";\n\n/** The onboarding wizard route on the wallet origin. */\nexport const ONBOARD_PATH = \"/onboard\";\n\n/** The manage wallet route on the wallet origin. */\nexport const MANAGE_PATH = \"/manage\";\n\n/** The identity providers a partner can name in the `signIn` hint. */\nexport const SIGN_IN_HINTS = [\"assetera-marketplace\"] as const;\n\n/** A named identity provider the wallet may use for a silent sign-in. */\nexport type SignInHint = (typeof SIGN_IN_HINTS)[number];\n\n/** True when `value` is one of {@link SIGN_IN_HINTS}. */\nexport function isSignInHint(value: unknown): value is SignInHint {\n return (SIGN_IN_HINTS as readonly unknown[]).includes(value);\n}\n\n/** Every message carries this prefix in `type`, so both sides can ignore unrelated `postMessage` traffic. */\nexport const MESSAGE_PREFIX = \"assetera-wallet:\" as const;\n\n/**\n * The EIP-1193 methods the pop-up answers (ADR-0054 D3). Anything else is refused with 4200. Read-only chain\n * calls (`eth_call`, `eth_getBalance`, …) do not go through the pop-up; wagmi sends them to its own transports.\n */\nexport const SUPPORTED_METHODS = [\n \"eth_requestAccounts\",\n \"eth_accounts\",\n \"eth_chainId\",\n \"wallet_switchEthereumChain\",\n \"personal_sign\",\n \"eth_signTypedData_v4\",\n \"eth_sendTransaction\",\n] as const;\n\nexport type SupportedMethod = (typeof SUPPORTED_METHODS)[number];\n\nexport function isSupportedMethod(method: string): method is SupportedMethod {\n return (SUPPORTED_METHODS as readonly string[]).includes(method);\n}\n\n/** EIP-1193 / EIP-1474 error codes the pop-up uses. */\nexport const RpcErrorCode = {\n /** The client rejected the request in the pop-up. */\n UserRejected: 4001,\n /** Not connected yet (no `eth_requestAccounts` approved in this pop-up). */\n Unauthorized: 4100,\n /** The method is not in SUPPORTED_METHODS. */\n UnsupportedMethod: 4200,\n /** The pop-up closed, or the wallet session ended. */\n Disconnected: 4900,\n /** `wallet_switchEthereumChain` to a chain the wallet does not offer. */\n UnrecognizedChain: 4902,\n /** Malformed params. */\n InvalidParams: -32602,\n /** Anything unexpected inside the wallet. */\n Internal: -32603,\n} as const;\n\nexport type RpcErrorCode = (typeof RpcErrorCode)[keyof typeof RpcErrorCode];\n\nexport interface RpcError {\n code: number;\n message: string;\n data?: unknown;\n}\n\n// --- pop-up → opener ---------------------------------------------------------------------------------\n\n/** The pop-up is loaded and accepts requests from this opener. */\nexport interface ReadyMessage {\n type: `${typeof MESSAGE_PREFIX}ready`;\n v: typeof PROTOCOL_VERSION;\n /** Shown to the partner for diagnostics only; the partner must not rely on it for anything. */\n walletVersion?: string;\n}\n\n/** The answer to one `request`, matched by `id`. Exactly one of `result` / `error`. */\nexport type ResponseMessage =\n | { type: `${typeof MESSAGE_PREFIX}response`; v: typeof PROTOCOL_VERSION; id: string; result: unknown }\n | { type: `${typeof MESSAGE_PREFIX}response`; v: typeof PROTOCOL_VERSION; id: string; error: RpcError };\n\n/** EIP-1193 provider events, forwarded to the partner. */\nexport type EventMessage =\n | {\n type: `${typeof MESSAGE_PREFIX}event`;\n v: typeof PROTOCOL_VERSION;\n event: \"accountsChanged\";\n data: `0x${string}`[];\n }\n | {\n type: `${typeof MESSAGE_PREFIX}event`;\n v: typeof PROTOCOL_VERSION;\n event: \"chainChanged\";\n data: `0x${string}`;\n }\n | {\n type: `${typeof MESSAGE_PREFIX}event`;\n v: typeof PROTOCOL_VERSION;\n event: \"disconnect\";\n data: RpcError;\n };\n\n/**\n * How well the client's Assetera Wallet is protected. The values are the ones the wallet site shows:\n *\n * - `add-factor`: there is no passkey and no authenticator app yet.\n * - `save-codes`: recovery codes exist, but the client has not confirmed saving them.\n * - `create-codes`: a factor exists, but there are no recovery codes.\n * - `protected`: a factor exists and the recovery codes are saved.\n * - `unknown`: the wallet could not read the state.\n */\nexport type WalletProtection = \"unknown\" | \"add-factor\" | \"save-codes\" | \"create-codes\" | \"protected\";\n\n/** The wallet security status sent by a manage (or connect) pop-up. */\nexport interface WalletSecurityStatus {\n /** Overall result, the same values the wallet site shows. */\n protection: WalletProtection;\n /** Passkeys registered for signing (Dynamic step-up), not sign-in factors. */\n passkeys: number;\n /** Authenticator apps (TOTP) registered for signing (Dynamic step-up). */\n authenticatorApps: number;\n}\n\n/**\n * The wallet reports the security status while a pop-up is open. The partner cannot ask for it. It never\n * carries a token, an identity or a credential.\n */\nexport interface SecurityMessage {\n type: `${typeof MESSAGE_PREFIX}security`;\n v: typeof PROTOCOL_VERSION;\n data: WalletSecurityStatus;\n}\n\n/** One account of the Assetera Wallet that the client already shared with this partner, with its name. */\nexport interface WalletAccountName {\n address: `0x${string}`;\n name: string;\n}\n\n/**\n * The wallet reports the names of the accounts the client already shared with this partner. The partner cannot\n * ask for it and the wallet never names an account the partner does not already know. It never carries a token\n * or any other data.\n */\nexport interface AccountsMessage {\n type: `${typeof MESSAGE_PREFIX}accounts`;\n v: typeof PROTOCOL_VERSION;\n data: WalletAccountName[];\n}\n\n/**\n * The onboarding wizard finished: the client accepted the wallet terms and has an Assetera Wallet on `chain`.\n * `created` is `true` when the wallet was created in this run, `false` when the wizard returned the client's\n * existing wallet. The wallet is not registered with any compliance service; that is the partner's step.\n */\nexport interface OnboardedMessage {\n type: `${typeof MESSAGE_PREFIX}onboarded`;\n v: typeof PROTOCOL_VERSION;\n address: `0x${string}`;\n chain: string;\n created: boolean;\n /**\n * @deprecated Sent by wallet versions that registered the wallet themselves (before ADR-0059). Ignored.\n */\n status?: \"approved\" | \"pending\";\n}\n\n/** The onboarding wizard did not produce a wallet. `message` is optional diagnostics for the partner. */\nexport interface OnboardCancelledMessage {\n type: `${typeof MESSAGE_PREFIX}onboard-cancelled`;\n v: typeof PROTOCOL_VERSION;\n reason: \"user\" | \"refused\" | \"error\";\n message?: string;\n}\n\nexport type WalletToPartnerMessage =\n | ReadyMessage\n | ResponseMessage\n | EventMessage\n | SecurityMessage\n | AccountsMessage\n | OnboardedMessage\n | OnboardCancelledMessage;\n\n// --- opener → pop-up ---------------------------------------------------------------------------------\n\nexport interface RequestMessage {\n type: `${typeof MESSAGE_PREFIX}request`;\n v: typeof PROTOCOL_VERSION;\n /** Unique per request within one connection; the response carries it back. */\n id: string;\n method: string;\n params?: unknown[] | Record<string, unknown>;\n}\n\n/** The partner disconnects (for example the user clicked \"Disconnect\" in the partner page). */\nexport interface DisconnectMessage {\n type: `${typeof MESSAGE_PREFIX}disconnect`;\n v: typeof PROTOCOL_VERSION;\n}\n\nexport type PartnerToWalletMessage = RequestMessage | DisconnectMessage;\n\n// --- guards ------------------------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction hasType(value: unknown, suffix: string): value is Record<string, unknown> {\n return isRecord(value) && value.type === `${MESSAGE_PREFIX}${suffix}` && value.v === PROTOCOL_VERSION;\n}\n\nexport function isReadyMessage(value: unknown): value is ReadyMessage {\n return hasType(value, \"ready\");\n}\n\nexport function isResponseMessage(value: unknown): value is ResponseMessage {\n return (\n hasType(value, \"response\") &&\n typeof value.id === \"string\" &&\n (\"result\" in value || (isRecord(value.error) && typeof value.error.code === \"number\"))\n );\n}\n\nexport function isEventMessage(value: unknown): value is EventMessage {\n return (\n hasType(value, \"event\") &&\n (value.event === \"accountsChanged\" || value.event === \"chainChanged\" || value.event === \"disconnect\")\n );\n}\n\nconst WALLET_PROTECTIONS: readonly WalletProtection[] = [\n \"unknown\",\n \"add-factor\",\n \"save-codes\",\n \"create-codes\",\n \"protected\",\n];\n\n/** A factor count: a whole number, zero or more. */\nfunction isCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\n/** True for a `security` message with a known `protection` value and whole, non-negative factor counts. */\nexport function isSecurityMessage(value: unknown): value is SecurityMessage {\n if (!hasType(value, \"security\")) return false;\n const data = value.data;\n return (\n isRecord(data) &&\n typeof data.protection === \"string\" &&\n (WALLET_PROTECTIONS as readonly string[]).includes(data.protection) &&\n isCount(data.passkeys) &&\n isCount(data.authenticatorApps)\n );\n}\n\n/** The largest number of accounts one `accounts` message may carry. */\nconst MAX_ACCOUNT_NAMES = 50;\n\n/** True when `value` has a control character: C0, DEL or C1. */\nfunction hasControlCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) return true;\n }\n return false;\n}\n\n/** A name: a string whose trimmed length is 1 to 64 and that has no control characters. */\nfunction isAccountName(value: unknown): value is string {\n if (typeof value !== \"string\") return false;\n if (hasControlCharacter(value)) return false;\n const trimmed = value.trim();\n return trimmed.length >= 1 && trimmed.length <= 64;\n}\n\n/** True for an `accounts` message with at most 50 named accounts. */\nexport function isAccountsMessage(value: unknown): value is AccountsMessage {\n if (!hasType(value, \"accounts\")) return false;\n const data = value.data;\n return (\n Array.isArray(data) &&\n data.length <= MAX_ACCOUNT_NAMES &&\n data.every(\n (entry: unknown) =>\n isRecord(entry) &&\n typeof entry.address === \"string\" &&\n EVM_ADDRESS_RE.test(entry.address) &&\n isAccountName(entry.name),\n )\n );\n}\n\nexport function isRequestMessage(value: unknown): value is RequestMessage {\n return hasType(value, \"request\") && typeof value.id === \"string\" && typeof value.method === \"string\";\n}\n\nexport function isDisconnectMessage(value: unknown): value is DisconnectMessage {\n return hasType(value, \"disconnect\");\n}\n\n/** `0x` followed by exactly 40 hexadecimal digits, the shape of an EVM address. */\nconst EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\n\nexport function isOnboardedMessage(value: unknown): value is OnboardedMessage {\n return (\n hasType(value, \"onboarded\") &&\n typeof value.address === \"string\" &&\n EVM_ADDRESS_RE.test(value.address) &&\n typeof value.chain === \"string\" &&\n // `created` is new; an older wallet sent `status` instead and always created or reused a wallet.\n (typeof value.created === \"boolean\" || value.status === \"approved\" || value.status === \"pending\")\n );\n}\n\nexport function isOnboardCancelledMessage(value: unknown): value is OnboardCancelledMessage {\n return (\n hasType(value, \"onboard-cancelled\") &&\n (value.reason === \"user\" || value.reason === \"refused\" || value.reason === \"error\")\n );\n}\n\n/** A CAIP-2 EVM chain id, for example `eip155:80002` (Polygon Amoy) or `eip155:1` (mainnet). */\nexport function isCaip2EvmChain(value: string): boolean {\n return /^eip155:\\d{1,32}$/.test(value);\n}\n\n/**\n * The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. `signIn` adds the\n * optional sign-in hint; it is only a hint and the wallet may ignore it.\n */\nexport function connectUrl(walletUrl: string, partnerOrigin: string, signIn?: SignInHint): string {\n const url = new URL(CONNECT_PATH, walletUrl);\n url.searchParams.set(\"origin\", partnerOrigin);\n url.searchParams.set(\"v\", String(PROTOCOL_VERSION));\n if (signIn !== undefined) url.searchParams.set(\"signIn\", signIn);\n return url.toString();\n}\n\n/**\n * The URL the partner opens for the onboarding wizard. `partnerOrigin` is `window.location.origin` of the\n * partner page; `chain` is the CAIP-2 chain id the new wallet should be created on; `locale` is passed as `lang`\n * when the partner wants a specific wizard language. `signIn` adds the optional sign-in hint; it is only a hint\n * and the wallet may ignore it.\n */\nexport function onboardUrl(\n walletUrl: string,\n partnerOrigin: string,\n options: { chain: string; locale?: string; add?: boolean; signIn?: SignInHint },\n): string {\n const url = new URL(ONBOARD_PATH, walletUrl);\n url.searchParams.set(\"origin\", partnerOrigin);\n url.searchParams.set(\"v\", String(PROTOCOL_VERSION));\n url.searchParams.set(\"chain\", options.chain);\n if (options.locale !== undefined) url.searchParams.set(\"lang\", options.locale);\n if (options.add) url.searchParams.set(\"add\", \"1\");\n if (options.signIn !== undefined) url.searchParams.set(\"signIn\", options.signIn);\n return url.toString();\n}\n\n/**\n * The URL the partner opens to manage the wallet. `partnerOrigin` is `window.location.origin` of the partner\n * page. `locale` is passed as `lang` when the partner wants a specific language. `signIn` adds the optional\n * sign-in hint; it is only a hint and the wallet may ignore it.\n */\nexport function manageUrl(\n walletUrl: string,\n partnerOrigin: string,\n options: { locale?: string; signIn?: SignInHint } = {},\n): string {\n const url = new URL(MANAGE_PATH, walletUrl);\n url.searchParams.set(\"origin\", partnerOrigin);\n url.searchParams.set(\"v\", String(PROTOCOL_VERSION));\n if (options.locale !== undefined) url.searchParams.set(\"lang\", options.locale);\n if (options.signIn !== undefined) url.searchParams.set(\"signIn\", options.signIn);\n return url.toString();\n}\n"]}
@@ -57,6 +57,14 @@
57
57
  * authenticator app, recovery codes). The pop-up checks the claimed origin against its partner list, posts
58
58
  * `ready` to `window.opener` (the same message as `/connect`) and then posts `security` messages. It never
59
59
  * answers `request` messages.
60
+ *
61
+ * ## Account names
62
+ *
63
+ * While a pop-up is open it may also post `accounts` messages. Each entry names one account the client has
64
+ * already shared with THIS partner, so the partner can show a name next to the address. The wallet never sends
65
+ * an account the partner does not already know. A manage pop-up may send the message, and an onboarding pop-up
66
+ * may send it after it reported the address. The message is only sent while a pop-up is open, never on request
67
+ * of the partner. It carries no token and no other data.
60
68
  */
61
69
  declare const PROTOCOL_VERSION: 1;
62
70
  /** The pop-up route on the wallet origin. */
@@ -167,6 +175,21 @@ interface SecurityMessage {
167
175
  v: typeof PROTOCOL_VERSION;
168
176
  data: WalletSecurityStatus;
169
177
  }
178
+ /** One account of the Assetera Wallet that the client already shared with this partner, with its name. */
179
+ interface WalletAccountName {
180
+ address: `0x${string}`;
181
+ name: string;
182
+ }
183
+ /**
184
+ * The wallet reports the names of the accounts the client already shared with this partner. The partner cannot
185
+ * ask for it and the wallet never names an account the partner does not already know. It never carries a token
186
+ * or any other data.
187
+ */
188
+ interface AccountsMessage {
189
+ type: `${typeof MESSAGE_PREFIX}accounts`;
190
+ v: typeof PROTOCOL_VERSION;
191
+ data: WalletAccountName[];
192
+ }
170
193
  /**
171
194
  * The onboarding wizard finished: the client accepted the wallet terms and has an Assetera Wallet on `chain`.
172
195
  * `created` is `true` when the wallet was created in this run, `false` when the wizard returned the client's
@@ -190,7 +213,7 @@ interface OnboardCancelledMessage {
190
213
  reason: "user" | "refused" | "error";
191
214
  message?: string;
192
215
  }
193
- type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | SecurityMessage | OnboardedMessage | OnboardCancelledMessage;
216
+ type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | SecurityMessage | AccountsMessage | OnboardedMessage | OnboardCancelledMessage;
194
217
  interface RequestMessage {
195
218
  type: `${typeof MESSAGE_PREFIX}request`;
196
219
  v: typeof PROTOCOL_VERSION;
@@ -210,6 +233,8 @@ declare function isResponseMessage(value: unknown): value is ResponseMessage;
210
233
  declare function isEventMessage(value: unknown): value is EventMessage;
211
234
  /** True for a `security` message with a known `protection` value and whole, non-negative factor counts. */
212
235
  declare function isSecurityMessage(value: unknown): value is SecurityMessage;
236
+ /** True for an `accounts` message with at most 50 named accounts. */
237
+ declare function isAccountsMessage(value: unknown): value is AccountsMessage;
213
238
  declare function isRequestMessage(value: unknown): value is RequestMessage;
214
239
  declare function isDisconnectMessage(value: unknown): value is DisconnectMessage;
215
240
  declare function isOnboardedMessage(value: unknown): value is OnboardedMessage;
@@ -243,4 +268,4 @@ declare function manageUrl(walletUrl: string, partnerOrigin: string, options?: {
243
268
  signIn?: SignInHint;
244
269
  }): string;
245
270
 
246
- export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, type SecurityMessage, type SignInHint, type SupportedMethod, type WalletProtection, type WalletSecurityStatus, type WalletToPartnerMessage, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl };
271
+ export { type AccountsMessage, CONNECT_PATH, type DisconnectMessage, type EventMessage, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, type SecurityMessage, type SignInHint, type SupportedMethod, type WalletAccountName, type WalletProtection, type WalletSecurityStatus, type WalletToPartnerMessage, connectUrl, isAccountsMessage, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl };
@@ -57,6 +57,14 @@
57
57
  * authenticator app, recovery codes). The pop-up checks the claimed origin against its partner list, posts
58
58
  * `ready` to `window.opener` (the same message as `/connect`) and then posts `security` messages. It never
59
59
  * answers `request` messages.
60
+ *
61
+ * ## Account names
62
+ *
63
+ * While a pop-up is open it may also post `accounts` messages. Each entry names one account the client has
64
+ * already shared with THIS partner, so the partner can show a name next to the address. The wallet never sends
65
+ * an account the partner does not already know. A manage pop-up may send the message, and an onboarding pop-up
66
+ * may send it after it reported the address. The message is only sent while a pop-up is open, never on request
67
+ * of the partner. It carries no token and no other data.
60
68
  */
61
69
  declare const PROTOCOL_VERSION: 1;
62
70
  /** The pop-up route on the wallet origin. */
@@ -167,6 +175,21 @@ interface SecurityMessage {
167
175
  v: typeof PROTOCOL_VERSION;
168
176
  data: WalletSecurityStatus;
169
177
  }
178
+ /** One account of the Assetera Wallet that the client already shared with this partner, with its name. */
179
+ interface WalletAccountName {
180
+ address: `0x${string}`;
181
+ name: string;
182
+ }
183
+ /**
184
+ * The wallet reports the names of the accounts the client already shared with this partner. The partner cannot
185
+ * ask for it and the wallet never names an account the partner does not already know. It never carries a token
186
+ * or any other data.
187
+ */
188
+ interface AccountsMessage {
189
+ type: `${typeof MESSAGE_PREFIX}accounts`;
190
+ v: typeof PROTOCOL_VERSION;
191
+ data: WalletAccountName[];
192
+ }
170
193
  /**
171
194
  * The onboarding wizard finished: the client accepted the wallet terms and has an Assetera Wallet on `chain`.
172
195
  * `created` is `true` when the wallet was created in this run, `false` when the wizard returned the client's
@@ -190,7 +213,7 @@ interface OnboardCancelledMessage {
190
213
  reason: "user" | "refused" | "error";
191
214
  message?: string;
192
215
  }
193
- type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | SecurityMessage | OnboardedMessage | OnboardCancelledMessage;
216
+ type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | SecurityMessage | AccountsMessage | OnboardedMessage | OnboardCancelledMessage;
194
217
  interface RequestMessage {
195
218
  type: `${typeof MESSAGE_PREFIX}request`;
196
219
  v: typeof PROTOCOL_VERSION;
@@ -210,6 +233,8 @@ declare function isResponseMessage(value: unknown): value is ResponseMessage;
210
233
  declare function isEventMessage(value: unknown): value is EventMessage;
211
234
  /** True for a `security` message with a known `protection` value and whole, non-negative factor counts. */
212
235
  declare function isSecurityMessage(value: unknown): value is SecurityMessage;
236
+ /** True for an `accounts` message with at most 50 named accounts. */
237
+ declare function isAccountsMessage(value: unknown): value is AccountsMessage;
213
238
  declare function isRequestMessage(value: unknown): value is RequestMessage;
214
239
  declare function isDisconnectMessage(value: unknown): value is DisconnectMessage;
215
240
  declare function isOnboardedMessage(value: unknown): value is OnboardedMessage;
@@ -243,4 +268,4 @@ declare function manageUrl(walletUrl: string, partnerOrigin: string, options?: {
243
268
  signIn?: SignInHint;
244
269
  }): string;
245
270
 
246
- export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, type SecurityMessage, type SignInHint, type SupportedMethod, type WalletProtection, type WalletSecurityStatus, type WalletToPartnerMessage, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl };
271
+ export { type AccountsMessage, CONNECT_PATH, type DisconnectMessage, type EventMessage, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, type SecurityMessage, type SignInHint, type SupportedMethod, type WalletAccountName, type WalletProtection, type WalletSecurityStatus, type WalletToPartnerMessage, connectUrl, isAccountsMessage, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl };
package/dist/protocol.js CHANGED
@@ -1,3 +1,3 @@
1
- export { CONNECT_PATH, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, PROTOCOL_VERSION, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl } from './chunk-H7PEM735.js';
1
+ export { CONNECT_PATH, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, PROTOCOL_VERSION, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, connectUrl, isAccountsMessage, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl } from './chunk-ZEOGKINA.js';
2
2
  //# sourceMappingURL=protocol.js.map
3
3
  //# sourceMappingURL=protocol.js.map
@@ -1,4 +1,4 @@
1
- import { WalletSecurityStatus, SignInHint } from './protocol.js';
1
+ import { WalletSecurityStatus, WalletAccountName, SignInHint } from './protocol.js';
2
2
 
3
3
  /**
4
4
  * EIP-1193 provider for the Assetera Wallet pop-up — the opener side of the ADR-0054 D3/D4 protocol.
@@ -13,8 +13,8 @@ interface RequestArguments {
13
13
  method: string;
14
14
  params?: unknown[] | Record<string, unknown>;
15
15
  }
16
- /** EIP-1193 provider events emitted by the pop-up, plus the wallet security status. */
17
- type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect" | "assetera_security";
16
+ /** EIP-1193 provider events emitted by the pop-up, plus the wallet security status and account names. */
17
+ type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect" | "assetera_security" | "assetera_accounts";
18
18
  /**
19
19
  * Listener shape for EIP-1193 provider events. `never[]` accepts a listener with any concrete parameter list
20
20
  * (for example wagmi's `(accounts: string[]) => void`), while internal emission stays type-safe via a cast.
@@ -31,6 +31,29 @@ interface AsseteraWalletProvider {
31
31
  * does not clear it.
32
32
  */
33
33
  lastSecurityStatus(): WalletSecurityStatus | undefined;
34
+ /**
35
+ * The last account names reported by a wallet pop-up, or `undefined` when none arrived yet. The returned list
36
+ * is a copy. A closed pop-up does not clear it.
37
+ */
38
+ lastAccountNames(): WalletAccountName[] | undefined;
39
+ /**
40
+ * Open the pop-up NOW, inside the caller's click, for a signature that is sent later. Use it when the app must
41
+ * wait for something (a firm quote, a fee) between the click and the signing request: without it, the request
42
+ * would open the pop-up after an `await`, outside the click, and the browser would block it. A later
43
+ * `request` reuses the pop-up. Synchronous; it never throws.
44
+ */
45
+ prepareSigning(): PreparedSigning;
46
+ }
47
+ /** The handle {@link AsseteraWalletProvider.prepareSigning} returns. */
48
+ interface PreparedSigning {
49
+ /** `false` when the browser blocked the pop-up. The caller should then ask for another click. */
50
+ readonly opened: boolean;
51
+ /**
52
+ * Give the pop-up back when no request followed (the quote failed, the client cancelled). It closes the
53
+ * pop-up only when THIS call opened it and no request was sent since; otherwise it does nothing. Safe to call
54
+ * more than once.
55
+ */
56
+ release(): void;
34
57
  }
35
58
  /** Options for {@link createAsseteraWalletProvider}. */
36
59
  interface AsseteraWalletProviderOptions {
@@ -60,4 +83,4 @@ declare class ProviderRpcError extends Error {
60
83
  */
61
84
  declare function createAsseteraWalletProvider(options: AsseteraWalletProviderOptions): AsseteraWalletProvider;
62
85
 
63
- export { type AsseteraWalletProvider as A, type ProviderEvent as P, type RequestArguments as R, type AsseteraWalletProviderOptions as a, type ProviderListener as b, ProviderRpcError as c, createAsseteraWalletProvider as d };
86
+ export { type AsseteraWalletProvider as A, type PreparedSigning as P, type RequestArguments as R, type AsseteraWalletProviderOptions as a, type ProviderEvent as b, type ProviderListener as c, ProviderRpcError as d, createAsseteraWalletProvider as e };