@tempoxyz/id 0.0.0-pr-751.sha-6fdf21b → 0.0.0-pr-749.sha-e9face1

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.
@@ -4,9 +4,9 @@ import {
4
4
  name,
5
5
  parseName,
6
6
  pending
7
- } from "./chunk-QL7UYVGP.js";
7
+ } from "./chunk-CMIMUIV7.js";
8
8
  import "./chunk-HWONYWNC.js";
9
- import "./chunk-2BJJYAAI.js";
9
+ import "./chunk-UGIWBXMZ.js";
10
10
  import "./chunk-MLKGABMK.js";
11
11
  export {
12
12
  attach,
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  PendingNotFoundError,
7
7
  RequestError
8
- } from "./chunk-2BJJYAAI.js";
8
+ } from "./chunk-UGIWBXMZ.js";
9
9
  import "./chunk-MLKGABMK.js";
10
10
 
11
11
  // ../../accounts/src/internal/BackendCookie.ts
@@ -4,8 +4,8 @@ import {
4
4
  machines,
5
5
  prompt,
6
6
  waiting
7
- } from "./chunk-OR4H7ZKK.js";
8
- import "./chunk-2BJJYAAI.js";
7
+ } from "./chunk-S3QDABXG.js";
8
+ import "./chunk-UGIWBXMZ.js";
9
9
  import "./chunk-MLKGABMK.js";
10
10
  export {
11
11
  create,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  dialog_exports,
3
3
  redirect_exports
4
- } from "./chunk-MLMRZMAK.js";
4
+ } from "./chunk-YXEQ42DK.js";
5
5
  import {
6
6
  connections_exports
7
- } from "./chunk-QL7UYVGP.js";
7
+ } from "./chunk-CMIMUIV7.js";
8
8
  import {
9
9
  AccessKeyRequiredError,
10
10
  AccessKey_exports,
@@ -43,7 +43,7 @@ import {
43
43
  unlisted,
44
44
  user,
45
45
  withoutKey
46
- } from "./chunk-2BJJYAAI.js";
46
+ } from "./chunk-UGIWBXMZ.js";
47
47
  import {
48
48
  __export
49
49
  } from "./chunk-MLKGABMK.js";
@@ -9,7 +9,7 @@ import {
9
9
  from,
10
10
  json,
11
11
  post
12
- } from "./chunk-2BJJYAAI.js";
12
+ } from "./chunk-UGIWBXMZ.js";
13
13
  import {
14
14
  __export
15
15
  } from "./chunk-MLKGABMK.js";
@@ -2,7 +2,7 @@ import {
2
2
  openPopup,
3
3
  received,
4
4
  watchPopup
5
- } from "./chunk-2BJJYAAI.js";
5
+ } from "./chunk-UGIWBXMZ.js";
6
6
 
7
7
  // ../../accounts/src/internal/Sheet.ts
8
8
  import {
@@ -461,13 +461,11 @@ function frame(options) {
461
461
  adopt();
462
462
  const dialog = document.createElement("dialog");
463
463
  dialog.setAttribute(attribute, "");
464
- dialog.setAttribute("aria-label", "Add funds with Tempo");
464
+ dialog.setAttribute("aria-label", options.label);
465
465
  const element = document.createElement("iframe");
466
- element.setAttribute("allow", "payment");
467
- element.setAttribute(
468
- "sandbox",
469
- "allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
470
- );
466
+ element.setAttribute("allow", options.allow);
467
+ element.setAttribute("referrerpolicy", "origin");
468
+ element.setAttribute("sandbox", options.sandbox);
471
469
  element.setAttribute("title", "Tempo ID");
472
470
  element.style.height = "420px";
473
471
  element.src = options.url;
@@ -489,7 +487,7 @@ function frame(options) {
489
487
  panel.setAttribute("data-panel", "");
490
488
  const text = document.createElement("p");
491
489
  text.setAttribute("aria-live", "polite");
492
- text.textContent = "Continue in a Tempo ID window to add funds.";
490
+ text.textContent = options.text;
493
491
  const primary = document.createElement("button");
494
492
  primary.setAttribute("data-primary", "");
495
493
  primary.type = "button";
@@ -39,12 +39,16 @@ __export(Accounts_exports, {
39
39
  // ../../accounts/src/actions/account.ts
40
40
  var account_exports = {};
41
41
  __export(account_exports, {
42
+ BlockedError: () => BlockedError,
43
+ OriginError: () => OriginError,
44
+ PageRequiredError: () => PageRequiredError,
42
45
  connection: () => connection,
43
46
  connections: () => connections,
44
47
  disconnect: () => disconnect,
45
48
  disconnectApp: () => disconnectApp,
46
49
  get: () => get,
47
50
  revokeAccessKey: () => revokeAccessKey,
51
+ revokeAccessKeys: () => revokeAccessKeys,
48
52
  signMessage: () => signMessage,
49
53
  signTypedData: () => signTypedData,
50
54
  updateAccessKey: () => updateAccessKey,
@@ -493,7 +497,141 @@ function withoutKey(body, options = {}) {
493
497
  };
494
498
  }
495
499
 
500
+ // ../../accounts/src/internal/Callback.ts
501
+ function received(value, options) {
502
+ if (typeof value !== "object" || value === null) return void 0;
503
+ const data = value;
504
+ if (data.type === `${options.prefix}.callback` && typeof data.url === "string")
505
+ return { url: data.url };
506
+ if (data.type !== `${options.prefix}.result` || typeof data.authorization !== "object" || data.authorization === null)
507
+ return void 0;
508
+ return {
509
+ authorization: data.authorization,
510
+ ...typeof data.state === "string" ? { state: data.state } : {}
511
+ };
512
+ }
513
+ function checkState(url, options) {
514
+ if (url.searchParams.getAll("state").at(-1) !== options.state)
515
+ throw new RequestError({
516
+ code: "invalid_request",
517
+ field: "state",
518
+ message: "Invalid `state` in the callback URL. Start sign-in again from this app.",
519
+ status: 400
520
+ });
521
+ }
522
+ function error2(url, options) {
523
+ const code = parameter(url, { ...options, name: "error" });
524
+ if (!code) return void 0;
525
+ return new RequestError({
526
+ code,
527
+ message: parameter(url, { ...options, name: "error_description" }) ?? code,
528
+ status: 0,
529
+ uri: parameter(url, { ...options, name: "error_uri" })
530
+ });
531
+ }
532
+ function parameter(url, options) {
533
+ const registered = new URL(options.redirectUri).searchParams.getAll(
534
+ options.name
535
+ ).length;
536
+ return url.searchParams.getAll(options.name)[registered];
537
+ }
538
+
539
+ // ../../accounts/src/internal/Chains.ts
540
+ var devIds = { devnet: 31318, localnet: 1337 };
541
+ var ids = { mainnet: 4217, testnet: 42431 };
542
+ function parameter2(options) {
543
+ const name = Object.keys(ids).find(
544
+ (key) => ids[key] === options.chainId
545
+ );
546
+ return name ?? String(options.chainId);
547
+ }
548
+
549
+ // ../../accounts/src/internal/Popup.ts
550
+ var closeGrace = 1e3;
551
+ var closeInterval = 100;
552
+ function openPopup(url) {
553
+ const width = 432;
554
+ const height = 420;
555
+ const left = window.screenX + (window.outerWidth - width) / 2;
556
+ const top = window.screenY + (window.outerHeight - height) / 2;
557
+ return window.open(
558
+ url,
559
+ "_blank",
560
+ `popup,width=${width},height=${height},left=${left},top=${top}`
561
+ );
562
+ }
563
+ function watchPopup(popup, options) {
564
+ let open2 = false;
565
+ let closedAt;
566
+ const listener = (event) => {
567
+ if (event.origin !== options.origin || event.source !== popup) return;
568
+ const data = event.data;
569
+ if (data?.type === "tempo-id:popup.open") {
570
+ open2 = true;
571
+ return;
572
+ }
573
+ const callback = received(data, { prefix: "tempo-id:popup" });
574
+ if (!callback) return;
575
+ stop();
576
+ options.onCallback(callback);
577
+ };
578
+ const interval = setInterval(() => {
579
+ if (!open2 || !popup.closed) return;
580
+ if (closedAt === void 0) {
581
+ closedAt = Date.now();
582
+ options.onClosed?.();
583
+ }
584
+ if (Date.now() - closedAt < closeGrace) return;
585
+ stop();
586
+ options.onClose();
587
+ }, closeInterval);
588
+ const stop = () => {
589
+ clearInterval(interval);
590
+ window.removeEventListener("message", listener);
591
+ };
592
+ window.addEventListener("message", listener);
593
+ return stop;
594
+ }
595
+ function apple() {
596
+ const agent = navigator.userAgent;
597
+ if (/iPad|iPhone|iPod/.test(agent)) return true;
598
+ return /Macintosh/.test(agent) && navigator.maxTouchPoints > 1;
599
+ }
600
+ function coinflow(options) {
601
+ const { amount, chainId, token: token2 } = options;
602
+ if (amount === void 0 || token2 !== "MACH") return false;
603
+ if (chainId !== ids.mainnet) return false;
604
+ return apple();
605
+ }
606
+ function activated() {
607
+ return navigator.userActivation?.isActive ?? true;
608
+ }
609
+
496
610
  // ../../accounts/src/actions/account.ts
611
+ var BlockedError = class extends Error {
612
+ name = "Actions.account.BlockedError";
613
+ constructor() {
614
+ super(
615
+ "The browser blocked the approval popup. Call the action in a click handler, before any `await`, or open the approval page in a frame or through a redirect."
616
+ );
617
+ }
618
+ };
619
+ var OriginError = class extends Error {
620
+ name = "Actions.account.OriginError";
621
+ constructor(options) {
622
+ super(
623
+ `Invalid redirect URI: ${options.redirectUri} is not on this page's origin, ${options.origin}. Call the action on a page of the redirect URI's origin, or open the approval page through a redirect.`
624
+ );
625
+ }
626
+ };
627
+ var PageRequiredError = class extends Error {
628
+ name = "Actions.account.PageRequiredError";
629
+ constructor() {
630
+ super(
631
+ "No browser window: the approval page opens in a frame or a popup only from a page. Open it through a redirect instead."
632
+ );
633
+ }
634
+ };
497
635
  async function connection(auth, options) {
498
636
  const url = new URL(
499
637
  `/v1/connection?${new URLSearchParams({ client_id: auth.clientId })}`,
@@ -592,20 +730,35 @@ async function get(auth, options = {}) {
592
730
  }
593
731
  async function revokeAccessKey(auth, options) {
594
732
  const { accessKey: accessKey2, accessToken: accessToken2, account: account2, chainId } = options;
595
- if (options.redirect) {
596
- const redirectUri = options.redirectUri ?? auth.redirectUri ?? (globalThis.location ? `${globalThis.location.origin}/` : void 0);
597
- if (!redirectUri)
598
- throw new Error("The approval page needs `redirectUri` to return to.");
599
- const url = new URL("/access-keys/revoke", auth.url);
600
- url.search = new URLSearchParams({
733
+ if (options.redirect || options.dialog) {
734
+ if (options.dialog && typeof document === "undefined")
735
+ throw new PageRequiredError();
736
+ const redirectUri = approvalRedirectUri(auth, options);
737
+ const query = {
601
738
  account: account2,
602
739
  address: accessKey2,
603
740
  chain_id: String(chainId),
604
741
  client_id: auth.clientId,
605
742
  redirect_uri: redirectUri,
606
743
  ...options.state !== void 0 ? { state: options.state } : {}
607
- }).toString();
608
- return { url: url.href };
744
+ };
745
+ if (!options.dialog) {
746
+ const url2 = new URL("/access-keys/revoke", auth.url);
747
+ url2.search = new URLSearchParams(query).toString();
748
+ return { url: url2.href };
749
+ }
750
+ const url = await approve(auth, {
751
+ label: "Revoke access with Tempo",
752
+ mode: options.dialog,
753
+ noun: "revocation",
754
+ path: "/access-keys/revoke",
755
+ query,
756
+ signal: options.signal,
757
+ text: "Continue in a Tempo ID window to revoke access."
758
+ });
759
+ return {
760
+ transaction: transactionOf(url, { redirectUri }) ?? null
761
+ };
609
762
  }
610
763
  const json2 = {
611
764
  account: account2,
@@ -632,6 +785,34 @@ async function revokeAccessKey(auth, options) {
632
785
  );
633
786
  return body.receipt ? formatTransactionReceipt(body.receipt) : null;
634
787
  }
788
+ async function revokeAccessKeys(auth, options) {
789
+ const { account: account2, chainId, getFn, keyIds: keyIds2 } = options;
790
+ const json2 = {
791
+ account: account2,
792
+ chainId,
793
+ client_id: auth.clientId,
794
+ ...keyIds2 ? { keyIds: keyIds2 } : {}
795
+ };
796
+ const path = "/v1/account/access-keys/revoke";
797
+ const first = await json(await post(auth, path, { json: json2 }));
798
+ const body = await (async () => {
799
+ if (!("step" in first)) return first;
800
+ const deserialized = Authentication.deserializeOptions(first.step.options);
801
+ const assertion = Authentication.serializeResponse(
802
+ await Authentication.sign(
803
+ // ox reads `getFn` beside request options at runtime, which its types admit only beside a challenge.
804
+ getFn ? { ...deserialized, getFn } : deserialized
805
+ )
806
+ );
807
+ return await json(
808
+ await post(auth, path, { json: { ...json2, passkey: { assertion } } })
809
+ );
810
+ })();
811
+ return {
812
+ receipt: body.receipt ? formatTransactionReceipt(body.receipt) : null,
813
+ revoked: body.revoked
814
+ };
815
+ }
635
816
  async function signMessage(auth, options) {
636
817
  const { account: account2, chain, message } = options;
637
818
  const body = await json(
@@ -686,12 +867,11 @@ async function updateAccessKey(auth, options) {
686
867
  } : {},
687
868
  ...options.scopes ? { scopes: options.scopes } : {}
688
869
  };
689
- if (options.redirect) {
690
- const redirectUri = options.redirectUri ?? auth.redirectUri ?? (globalThis.location ? `${globalThis.location.origin}/` : void 0);
691
- if (!redirectUri)
692
- throw new Error("The approval page needs `redirectUri` to return to.");
693
- const url = new URL("/access-keys/update", auth.url);
694
- url.search = new URLSearchParams({
870
+ if (options.redirect || options.dialog) {
871
+ if (options.dialog && typeof document === "undefined")
872
+ throw new PageRequiredError();
873
+ const redirectUri = approvalRedirectUri(auth, options);
874
+ const query = {
695
875
  account: account2,
696
876
  address: accessKey2,
697
877
  chain_id: String(chainId),
@@ -702,8 +882,24 @@ async function updateAccessKey(auth, options) {
702
882
  pad: false,
703
883
  url: true
704
884
  })
705
- }).toString();
706
- return { url: url.href };
885
+ };
886
+ if (!options.dialog) {
887
+ const url2 = new URL("/access-keys/update", auth.url);
888
+ url2.search = new URLSearchParams(query).toString();
889
+ return { url: url2.href };
890
+ }
891
+ const url = await approve(auth, {
892
+ label: "Change access with Tempo",
893
+ mode: options.dialog,
894
+ noun: "change",
895
+ path: "/access-keys/update",
896
+ query,
897
+ signal: options.signal,
898
+ text: "Continue in a Tempo ID window to change access."
899
+ });
900
+ const transaction = transactionOf(url, { redirectUri });
901
+ if (!transaction) throw transactionOf.missing();
902
+ return { transaction };
707
903
  }
708
904
  const body = await json(
709
905
  await post(auth, "/v1/account/access-keys/update", {
@@ -716,9 +912,130 @@ async function updateAccessKey(auth, options) {
716
912
  }
717
913
  })
718
914
  );
719
- return formatTransactionReceipt(
720
- body.receipt
721
- );
915
+ return formatTransactionReceipt(body.receipt);
916
+ }
917
+ function approvalRedirectUri(auth, options) {
918
+ const redirectUri = options.redirectUri ?? auth.redirectUri ?? (globalThis.location ? `${globalThis.location.origin}/` : void 0);
919
+ if (!redirectUri)
920
+ throw new Error("The approval page needs `redirectUri` to return to.");
921
+ return redirectUri;
922
+ }
923
+ async function approve(auth, options) {
924
+ const { mode, path, query, signal } = options;
925
+ const redirectUri = query.redirect_uri;
926
+ signal?.throwIfAborted();
927
+ if (typeof document === "undefined") throw new PageRequiredError();
928
+ if (new URL(redirectUri).origin !== window.location.origin)
929
+ throw new OriginError({ origin: window.location.origin, redirectUri });
930
+ const origin = new URL(auth.url).origin;
931
+ const toUrl = (display) => {
932
+ const url = new URL(display === "frame" ? `/embed${path}` : path, auth.url);
933
+ url.search = new URLSearchParams({
934
+ ...query,
935
+ ...display === "popup" ? { display } : {}
936
+ }).toString();
937
+ return url.href;
938
+ };
939
+ const closed = () => new DOMException(`The user closed the ${options.noun}.`, "AbortError");
940
+ const finish = (value) => {
941
+ const url = new URL(value);
942
+ const refusal = error2(url, { redirectUri });
943
+ if (refusal) throw refusal;
944
+ return url;
945
+ };
946
+ const watch2 = async (popup) => {
947
+ let abort2;
948
+ let settled = false;
949
+ let unblock;
950
+ let unwatch;
951
+ try {
952
+ return await new Promise((resolve3, reject) => {
953
+ void import("./Sheet-2VUMVJXV.js").then(
954
+ (Sheet2) => {
955
+ if (settled) return;
956
+ unblock = Sheet2.waiting({
957
+ onCancel: () => reject(closed()),
958
+ popup
959
+ });
960
+ },
961
+ () => void 0
962
+ );
963
+ abort2 = () => reject(signal?.reason);
964
+ signal?.addEventListener("abort", abort2, { once: true });
965
+ unwatch = watchPopup(popup, {
966
+ onCallback: (value) => {
967
+ if (!("url" in value))
968
+ return reject(
969
+ new RequestError({
970
+ code: "invalid_request",
971
+ message: "Invalid return: the approval page posted no return URL. Try again.",
972
+ status: 0
973
+ })
974
+ );
975
+ try {
976
+ resolve3(finish(value.url));
977
+ } catch (error3) {
978
+ reject(error3);
979
+ }
980
+ },
981
+ onClose: () => reject(closed()),
982
+ onClosed: () => unblock?.(),
983
+ origin
984
+ });
985
+ });
986
+ } finally {
987
+ settled = true;
988
+ if (abort2) signal?.removeEventListener("abort", abort2);
989
+ unblock?.();
990
+ unwatch?.();
991
+ popup.close();
992
+ }
993
+ };
994
+ if (mode === "popup") {
995
+ const popup = openPopup(toUrl("popup"));
996
+ if (popup === null) throw new BlockedError();
997
+ return await watch2(popup);
998
+ }
999
+ const Sheet = await import("./Sheet-2VUMVJXV.js");
1000
+ signal?.throwIfAborted();
1001
+ let abort;
1002
+ let close;
1003
+ try {
1004
+ return await new Promise((resolve3, reject) => {
1005
+ abort = () => reject(signal?.reason);
1006
+ signal?.addEventListener("abort", abort, { once: true });
1007
+ close = Sheet.frame({
1008
+ // The page runs the passkey ceremony of the account's owner, for Tempo ID's origin.
1009
+ allow: `publickey-credentials-get ${origin}`,
1010
+ label: options.label,
1011
+ onCallback: (value) => {
1012
+ try {
1013
+ resolve3(finish(value));
1014
+ } catch (error3) {
1015
+ reject(error3);
1016
+ }
1017
+ },
1018
+ onCancel: () => reject(closed()),
1019
+ onPopup: (entry) => {
1020
+ const popup = openPopup(toUrl("popup"));
1021
+ if (popup === null) {
1022
+ if (!entry.automatic) reject(new BlockedError());
1023
+ return false;
1024
+ }
1025
+ close?.();
1026
+ watch2(popup).then(resolve3, reject);
1027
+ return true;
1028
+ },
1029
+ origin,
1030
+ sandbox: "allow-forms allow-same-origin allow-scripts",
1031
+ text: options.text,
1032
+ url: toUrl("frame")
1033
+ });
1034
+ });
1035
+ } finally {
1036
+ if (abort) signal?.removeEventListener("abort", abort);
1037
+ close?.();
1038
+ }
722
1039
  }
723
1040
  async function upgrade(auth, options) {
724
1041
  const { getFn, key } = options;
@@ -767,6 +1084,22 @@ function toConnection(body) {
767
1084
  app: body.app
768
1085
  };
769
1086
  }
1087
+ function transactionOf(url, options) {
1088
+ const transaction = parameter(url, {
1089
+ name: "transaction",
1090
+ redirectUri: options.redirectUri
1091
+ });
1092
+ if (transaction === void 0) return void 0;
1093
+ if (Hex.validate(transaction) && Hex.size(transaction) === 32)
1094
+ return transaction;
1095
+ throw transactionOf.missing();
1096
+ }
1097
+ transactionOf.missing = () => new RequestError({
1098
+ code: "invalid_request",
1099
+ field: "transaction",
1100
+ message: "Invalid `transaction` in the return URL: it is not a transaction hash. Check the account on Tempo ID, then try again.",
1101
+ status: 0
1102
+ });
770
1103
 
771
1104
  // ../../accounts/src/internal/Headless.ts
772
1105
  import { Authentication as Authentication2 } from "ox/webauthn";
@@ -783,18 +1116,6 @@ function from2(value) {
783
1116
  import { Address as Address2, Value } from "ox";
784
1117
  import { Addresses, Scopes, Selectors } from "viem/tempo";
785
1118
  import { defineToken, tokens as tokens2 } from "viem/tokens";
786
-
787
- // ../../accounts/src/internal/Chains.ts
788
- var devIds = { devnet: 31318, localnet: 1337 };
789
- var ids = { mainnet: 4217, testnet: 42431 };
790
- function parameter(options) {
791
- const name = Object.keys(ids).find(
792
- (key) => ids[key] === options.chainId
793
- );
794
- return name ?? String(options.chainId);
795
- }
796
-
797
- // ../../accounts/src/Permissions.ts
798
1119
  var DecimalsUnknownError = class extends Error {
799
1120
  name = "Permissions.DecimalsUnknownError";
800
1121
  constructor(options) {
@@ -3193,7 +3514,7 @@ var signInIds = /* @__PURE__ */ new Set([
3193
3514
  function plugin() {
3194
3515
  let loading;
3195
3516
  function load() {
3196
- loading ??= import("./dialog-CPAB7R2I.js").then((module) => module.dialog()).catch((error3) => {
3517
+ loading ??= import("./dialog-SWHB7N65.js").then((module) => module.dialog()).catch((error3) => {
3197
3518
  loading = void 0;
3198
3519
  throw error3;
3199
3520
  });
@@ -3211,7 +3532,9 @@ function plugin() {
3211
3532
  }
3212
3533
  return {
3213
3534
  callback: async () => (await get3()).callback(),
3214
- signIn: async (parameters) => (await get3()).signIn(parameters)
3535
+ revokeAccessKey: async (parameters) => (await get3()).revokeAccessKey(parameters),
3536
+ signIn: async (parameters) => (await get3()).signIn(parameters),
3537
+ updateAccessKey: async (parameters) => (await get3()).updateAccessKey(parameters)
3215
3538
  };
3216
3539
  },
3217
3540
  // The loaded plugin adds no member, so its `extend` runs once the module loads, and this one
@@ -3342,115 +3665,13 @@ function served(options) {
3342
3665
  // ../../accounts/src/actions/funding.ts
3343
3666
  var funding_exports = {};
3344
3667
  __export(funding_exports, {
3345
- BlockedError: () => BlockedError,
3346
- OriginError: () => OriginError,
3347
- PageRequiredError: () => PageRequiredError,
3668
+ BlockedError: () => BlockedError2,
3669
+ OriginError: () => OriginError2,
3670
+ PageRequiredError: () => PageRequiredError2,
3348
3671
  complete: () => complete2,
3349
3672
  open: () => open
3350
3673
  });
3351
-
3352
- // ../../accounts/src/internal/Callback.ts
3353
- function received(value, options) {
3354
- if (typeof value !== "object" || value === null) return void 0;
3355
- const data = value;
3356
- if (data.type === `${options.prefix}.callback` && typeof data.url === "string")
3357
- return { url: data.url };
3358
- if (data.type !== `${options.prefix}.result` || typeof data.authorization !== "object" || data.authorization === null)
3359
- return void 0;
3360
- return {
3361
- authorization: data.authorization,
3362
- ...typeof data.state === "string" ? { state: data.state } : {}
3363
- };
3364
- }
3365
- function checkState(url, options) {
3366
- if (url.searchParams.getAll("state").at(-1) !== options.state)
3367
- throw new RequestError({
3368
- code: "invalid_request",
3369
- field: "state",
3370
- message: "Invalid `state` in the callback URL. Start sign-in again from this app.",
3371
- status: 400
3372
- });
3373
- }
3374
- function error2(url, options) {
3375
- const code = parameter2(url, { ...options, name: "error" });
3376
- if (!code) return void 0;
3377
- return new RequestError({
3378
- code,
3379
- message: parameter2(url, { ...options, name: "error_description" }) ?? code,
3380
- status: 0,
3381
- uri: parameter2(url, { ...options, name: "error_uri" })
3382
- });
3383
- }
3384
- function parameter2(url, options) {
3385
- const registered = new URL(options.redirectUri).searchParams.getAll(
3386
- options.name
3387
- ).length;
3388
- return url.searchParams.getAll(options.name)[registered];
3389
- }
3390
-
3391
- // ../../accounts/src/internal/Popup.ts
3392
- var closeGrace = 1e3;
3393
- var closeInterval = 100;
3394
- function openPopup(url) {
3395
- const width = 432;
3396
- const height = 420;
3397
- const left = window.screenX + (window.outerWidth - width) / 2;
3398
- const top = window.screenY + (window.outerHeight - height) / 2;
3399
- return window.open(
3400
- url,
3401
- "_blank",
3402
- `popup,width=${width},height=${height},left=${left},top=${top}`
3403
- );
3404
- }
3405
- function watchPopup(popup, options) {
3406
- let open2 = false;
3407
- let closedAt;
3408
- const listener = (event) => {
3409
- if (event.origin !== options.origin || event.source !== popup) return;
3410
- const data = event.data;
3411
- if (data?.type === "tempo-id:popup.open") {
3412
- open2 = true;
3413
- return;
3414
- }
3415
- const callback = received(data, { prefix: "tempo-id:popup" });
3416
- if (!callback) return;
3417
- stop();
3418
- options.onCallback(callback);
3419
- };
3420
- const interval = setInterval(() => {
3421
- if (!open2 || !popup.closed) return;
3422
- if (closedAt === void 0) {
3423
- closedAt = Date.now();
3424
- options.onClosed?.();
3425
- }
3426
- if (Date.now() - closedAt < closeGrace) return;
3427
- stop();
3428
- options.onClose();
3429
- }, closeInterval);
3430
- const stop = () => {
3431
- clearInterval(interval);
3432
- window.removeEventListener("message", listener);
3433
- };
3434
- window.addEventListener("message", listener);
3435
- return stop;
3436
- }
3437
- function apple() {
3438
- const agent = navigator.userAgent;
3439
- if (/iPad|iPhone|iPod/.test(agent)) return true;
3440
- return /Macintosh/.test(agent) && navigator.maxTouchPoints > 1;
3441
- }
3442
- function coinflow(options) {
3443
- const { amount, chainId, token: token2 } = options;
3444
- if (amount === void 0 || token2 !== "MACH") return false;
3445
- if (chainId !== ids.mainnet) return false;
3446
- return apple();
3447
- }
3448
- function activated() {
3449
- return navigator.userActivation?.isActive ?? true;
3450
- }
3451
-
3452
- // ../../accounts/src/actions/funding.ts
3453
- var BlockedError = class extends Error {
3674
+ var BlockedError2 = class extends Error {
3454
3675
  name = "Actions.funding.BlockedError";
3455
3676
  constructor() {
3456
3677
  super(
@@ -3458,7 +3679,7 @@ var BlockedError = class extends Error {
3458
3679
  );
3459
3680
  }
3460
3681
  };
3461
- var OriginError = class extends Error {
3682
+ var OriginError2 = class extends Error {
3462
3683
  name = "Actions.funding.OriginError";
3463
3684
  constructor(options) {
3464
3685
  super(
@@ -3466,7 +3687,7 @@ var OriginError = class extends Error {
3466
3687
  );
3467
3688
  }
3468
3689
  };
3469
- var PageRequiredError = class extends Error {
3690
+ var PageRequiredError2 = class extends Error {
3470
3691
  name = "Actions.funding.PageRequiredError";
3471
3692
  constructor() {
3472
3693
  super(
@@ -3502,7 +3723,7 @@ async function open(auth, options) {
3502
3723
  if (typeof options.address === "object")
3503
3724
  Promise.resolve(options.address).catch(() => void 0);
3504
3725
  signal?.throwIfAborted();
3505
- if (typeof document === "undefined") throw new PageRequiredError();
3726
+ if (typeof document === "undefined") throw new PageRequiredError2();
3506
3727
  const mode = (() => {
3507
3728
  const value = options.mode ?? "frame";
3508
3729
  if (value !== "frame") return value;
@@ -3525,7 +3746,7 @@ async function open(auth, options) {
3525
3746
  ...entry.amount ? { amount: entry.amount } : {},
3526
3747
  // The page reads `mainnet` and `testnet` by name, and another chain by the name that the
3527
3748
  // deployment lists for its ID.
3528
- chain: parameter({ chainId: options.chainId ?? auth.chainId }),
3749
+ chain: parameter2({ chainId: options.chainId ?? auth.chainId }),
3529
3750
  client_id: auth.clientId,
3530
3751
  ...entry.mode === "popup" ? { display: entry.mode } : {},
3531
3752
  ...currency === void 0 ? {} : { funding_currency: currency },
@@ -3550,10 +3771,10 @@ async function open(auth, options) {
3550
3771
  return void 0;
3551
3772
  }
3552
3773
  if (new URL(redirectUri).origin !== window.location.origin)
3553
- throw new OriginError({ origin: window.location.origin, redirectUri });
3774
+ throw new OriginError2({ origin: window.location.origin, redirectUri });
3554
3775
  if (mode === "popup" && options.mode !== "popup" && !activated()) {
3555
3776
  const address = await abortable(read2(), { signal });
3556
- const Sheet = await import("./Sheet-D644QHD6.js");
3777
+ const Sheet = await import("./Sheet-2VUMVJXV.js");
3557
3778
  return await new Promise((resolve3, reject) => {
3558
3779
  const abort = () => {
3559
3780
  close();
@@ -3585,7 +3806,7 @@ async function open(auth, options) {
3585
3806
  const popup = openPopup(
3586
3807
  typeof options.address === "string" ? toUrl(options.address) : "about:blank"
3587
3808
  );
3588
- if (popup === null) throw new BlockedError();
3809
+ if (popup === null) throw new BlockedError2();
3589
3810
  return await watch(auth, {
3590
3811
  address: read2(),
3591
3812
  popup,
@@ -3604,7 +3825,7 @@ async function watch(auth, options) {
3604
3825
  try {
3605
3826
  return await new Promise(
3606
3827
  (resolve3, reject) => {
3607
- void import("./Sheet-D644QHD6.js").then(
3828
+ void import("./Sheet-2VUMVJXV.js").then(
3608
3829
  (Sheet) => {
3609
3830
  if (settled) return;
3610
3831
  unblock = Sheet.waiting({
@@ -3669,7 +3890,7 @@ function parse(url, options) {
3669
3890
  async function frame(auth, options) {
3670
3891
  const { redirectUri, signal, toUrl } = options;
3671
3892
  const address = await abortable(options.address, { signal });
3672
- const Sheet = await import("./Sheet-D644QHD6.js");
3893
+ const Sheet = await import("./Sheet-2VUMVJXV.js");
3673
3894
  signal?.throwIfAborted();
3674
3895
  let close;
3675
3896
  let abort;
@@ -3679,6 +3900,11 @@ async function frame(auth, options) {
3679
3900
  abort = () => reject(signal?.reason);
3680
3901
  signal?.addEventListener("abort", abort, { once: true });
3681
3902
  close = Sheet.frame({
3903
+ // Apple Pay and Google Pay need the `payment` permission in a frame, and their sheets open
3904
+ // popups from the frame's own clicks. The frame runs third-party scripts and nests the
3905
+ // card issuer's page.
3906
+ allow: "payment",
3907
+ label: "Add funds with Tempo",
3682
3908
  onCallback: (value) => resolve3(
3683
3909
  complete2(auth, { redirectUri, url: value }) ?? {
3684
3910
  status: "continued"
@@ -3694,7 +3920,7 @@ async function frame(auth, options) {
3694
3920
  })
3695
3921
  );
3696
3922
  if (popup === null) {
3697
- if (!entry.automatic) reject(new BlockedError());
3923
+ if (!entry.automatic) reject(new BlockedError2());
3698
3924
  return false;
3699
3925
  }
3700
3926
  close?.();
@@ -3705,6 +3931,8 @@ async function frame(auth, options) {
3705
3931
  return true;
3706
3932
  },
3707
3933
  origin: new URL(auth.url).origin,
3934
+ sandbox: "allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts",
3935
+ text: "Continue in a Tempo ID window to add funds.",
3708
3936
  url: toUrl(address)
3709
3937
  });
3710
3938
  }
@@ -4134,7 +4362,7 @@ function create4(options = {}) {
4134
4362
  function connections2() {
4135
4363
  if (!connectionsOptions)
4136
4364
  return Promise.reject(new ConnectionsRequiredError());
4137
- attached ??= import("./Connections-4J63W3O3.js").then(
4365
+ attached ??= import("./Connections-K44EJ6F7.js").then(
4138
4366
  (module) => module.attach(config, connectionsOptions)
4139
4367
  );
4140
4368
  return attached;
@@ -4183,7 +4411,7 @@ function create4(options = {}) {
4183
4411
  },
4184
4412
  handler: {
4185
4413
  async fetch(request2) {
4186
- server ??= import("./Server-GHH2TOPL.js").then(
4414
+ server ??= import("./Server-CAPWBFI3.js").then(
4187
4415
  (module) => module.create({
4188
4416
  accessKeys: connectionsOptions ? async () => (await connections2()).keyEndpoint : void 0,
4189
4417
  // The `backend` plugin's actions sit on the instance under its `id`.
@@ -4490,6 +4718,15 @@ export {
4490
4718
  user,
4491
4719
  tokens,
4492
4720
  withoutKey,
4721
+ received,
4722
+ checkState,
4723
+ error2,
4724
+ openPopup,
4725
+ watchPopup,
4726
+ coinflow,
4727
+ activated,
4728
+ revokeAccessKey,
4729
+ updateAccessKey,
4493
4730
  account_exports,
4494
4731
  authorizeUrl,
4495
4732
  request,
@@ -4511,17 +4748,12 @@ export {
4511
4748
  toSession,
4512
4749
  unlisted,
4513
4750
  from4 as from2,
4514
- received,
4515
- checkState,
4516
- error2,
4517
4751
  get2 as get,
4518
- openPopup,
4519
- watchPopup,
4520
- coinflow,
4521
- activated,
4522
4752
  open,
4523
4753
  funding_exports,
4754
+ KeyRequiredError,
4524
4755
  PendingNotFoundError,
4525
4756
  RequestError,
4757
+ SignedOutError2 as SignedOutError,
4526
4758
  Accounts_exports
4527
4759
  };
@@ -2,7 +2,7 @@ import {
2
2
  create,
3
3
  prompt,
4
4
  waiting
5
- } from "./chunk-OR4H7ZKK.js";
5
+ } from "./chunk-S3QDABXG.js";
6
6
  import {
7
7
  basePath
8
8
  } from "./chunk-HWONYWNC.js";
@@ -27,7 +27,7 @@ import {
27
27
  tokens,
28
28
  user,
29
29
  watchPopup
30
- } from "./chunk-2BJJYAAI.js";
30
+ } from "./chunk-UGIWBXMZ.js";
31
31
  import {
32
32
  __export
33
33
  } from "./chunk-MLKGABMK.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  env,
3
3
  login
4
- } from "../chunk-RXFSIUSG.js";
5
- import "../chunk-MLMRZMAK.js";
6
- import "../chunk-OR4H7ZKK.js";
7
- import "../chunk-QL7UYVGP.js";
4
+ } from "../chunk-6Y4DXPDA.js";
5
+ import "../chunk-YXEQ42DK.js";
6
+ import "../chunk-S3QDABXG.js";
7
+ import "../chunk-CMIMUIV7.js";
8
8
  import "../chunk-HWONYWNC.js";
9
- import "../chunk-2BJJYAAI.js";
9
+ import "../chunk-UGIWBXMZ.js";
10
10
  import "../chunk-MLKGABMK.js";
11
11
 
12
12
  // src/commands/login.ts
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  env,
3
3
  remove
4
- } from "../chunk-RXFSIUSG.js";
5
- import "../chunk-MLMRZMAK.js";
6
- import "../chunk-OR4H7ZKK.js";
7
- import "../chunk-QL7UYVGP.js";
4
+ } from "../chunk-6Y4DXPDA.js";
5
+ import "../chunk-YXEQ42DK.js";
6
+ import "../chunk-S3QDABXG.js";
7
+ import "../chunk-CMIMUIV7.js";
8
8
  import "../chunk-HWONYWNC.js";
9
- import "../chunk-2BJJYAAI.js";
9
+ import "../chunk-UGIWBXMZ.js";
10
10
  import "../chunk-MLKGABMK.js";
11
11
 
12
12
  // src/commands/logout.ts
@@ -2,12 +2,12 @@ import {
2
2
  env,
3
3
  signedOut,
4
4
  whoami
5
- } from "../chunk-RXFSIUSG.js";
6
- import "../chunk-MLMRZMAK.js";
7
- import "../chunk-OR4H7ZKK.js";
8
- import "../chunk-QL7UYVGP.js";
5
+ } from "../chunk-6Y4DXPDA.js";
6
+ import "../chunk-YXEQ42DK.js";
7
+ import "../chunk-S3QDABXG.js";
8
+ import "../chunk-CMIMUIV7.js";
9
9
  import "../chunk-HWONYWNC.js";
10
- import "../chunk-2BJJYAAI.js";
10
+ import "../chunk-UGIWBXMZ.js";
11
11
  import "../chunk-MLKGABMK.js";
12
12
 
13
13
  // src/commands/whoami.ts
@@ -2,17 +2,21 @@ import {
2
2
  callback,
3
3
  preload,
4
4
  signIn
5
- } from "./chunk-MLMRZMAK.js";
6
- import "./chunk-OR4H7ZKK.js";
5
+ } from "./chunk-YXEQ42DK.js";
6
+ import "./chunk-S3QDABXG.js";
7
7
  import {
8
8
  basePath
9
9
  } from "./chunk-HWONYWNC.js";
10
10
  import {
11
+ KeyRequiredError,
12
+ SignedOutError,
11
13
  accessKey,
12
14
  expired2 as expired,
13
15
  from2 as from,
14
- toSession
15
- } from "./chunk-2BJJYAAI.js";
16
+ revokeAccessKey,
17
+ toSession,
18
+ updateAccessKey
19
+ } from "./chunk-UGIWBXMZ.js";
16
20
  import "./chunk-MLKGABMK.js";
17
21
 
18
22
  // ../../accounts/src/plugins/dialog.ts
@@ -51,12 +55,52 @@ function dialog(options = {}) {
51
55
  return from({
52
56
  actions: (context) => {
53
57
  const config = configOf(context);
58
+ const target = (session, parameters) => {
59
+ const entries = [session?.key, ...session?.keys ?? []].filter(
60
+ (entry2) => entry2 !== void 0 && (parameters.accessKey === void 0 || entry2.keyAuthorization.keyId.toLowerCase() === parameters.accessKey.toLowerCase()) && (parameters.account === void 0 || entry2.account.toLowerCase() === parameters.account.toLowerCase())
61
+ );
62
+ const entry = entries.find(
63
+ (entry2) => Number(entry2.chainId) === (parameters.chainId ?? config.chainId)
64
+ ) ?? (parameters.chainId === void 0 && parameters.accessKey !== void 0 && entries.length === 1 ? entries[0] : void 0);
65
+ const accessKey2 = parameters.accessKey ?? entry?.keyAuthorization.keyId;
66
+ const account = parameters.account ?? entry?.account;
67
+ const chainId = parameters.chainId ?? (entry ? Number(entry.chainId) : void 0) ?? config.chainId;
68
+ if (accessKey2 && account) return { accessKey: accessKey2, account, chainId };
69
+ const { status } = context.session.status.get();
70
+ if (status === "pending" || status === "reauthorizing")
71
+ throw new SignedOutError({ pending: true });
72
+ if (session && !expired(session))
73
+ throw new KeyRequiredError();
74
+ throw new SignedOutError();
75
+ };
76
+ const sessionOf = async (parameters) => {
77
+ if (parameters.accessKey && parameters.account && parameters.chainId !== void 0)
78
+ return void 0;
79
+ return await context.session.load();
80
+ };
81
+ const modeOf = (mode) => mode ?? (popup && !crossOriginOpenerPolicy ? "popup" : "iframe");
54
82
  return {
55
83
  /**
56
84
  * Completes a popup's sign-in on the page of the redirect URI, and closes the popup.
57
85
  * Returns whether the page was the callback of a popup.
58
86
  */
59
87
  callback: () => callback(config),
88
+ /**
89
+ * Revokes the app's own access key on Tempo ID's approval page, in the dialog or a popup, and
90
+ * returns the hash of the transaction, or `null` for an access key that the chain held
91
+ * revoked already. Defaults to the session's access key.
92
+ */
93
+ // An async member rejects every failure, and still opens a popup within the click, since it
94
+ // runs at once up to its first `await`.
95
+ revokeAccessKey: async (parameters = {}) => revokeAccessKey(config, {
96
+ ...target(
97
+ context.session.get() ?? await sessionOf(parameters),
98
+ parameters
99
+ ),
100
+ dialog: modeOf(parameters.mode),
101
+ redirectUri: parameters.redirectUri ?? backendRedirectUri(config),
102
+ signal: parameters.signal
103
+ }),
60
104
  /**
61
105
  * Signs the user in, sets the instance's session, and returns it. With `backend`, the
62
106
  * backend keeps the session, and the call returns the session that the page reads.
@@ -83,7 +127,23 @@ function dialog(options = {}) {
83
127
  const session = toSession(result);
84
128
  await change.commit(session);
85
129
  return session;
86
- }
130
+ },
131
+ /**
132
+ * Changes the limits, the scopes, or both of the app's own access key on Tempo ID's approval
133
+ * page, in the dialog or a popup, and returns the hash of the transaction. Defaults to the
134
+ * session's access key.
135
+ */
136
+ updateAccessKey: async (parameters) => updateAccessKey(config, {
137
+ ...target(
138
+ context.session.get() ?? await sessionOf(parameters),
139
+ parameters
140
+ ),
141
+ dialog: modeOf(parameters.mode),
142
+ limits: parameters.limits,
143
+ redirectUri: parameters.redirectUri ?? backendRedirectUri(config),
144
+ scopes: parameters.scopes,
145
+ signal: parameters.signal
146
+ })
87
147
  };
88
148
  },
89
149
  // The plugin adds no member. It reads the instance's status, which only `extend` receives.
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "node": ">=24.21"
10
10
  },
11
11
  "name": "@tempoxyz/id",
12
- "version": "0.0.0-pr-751.sha-6fdf21b",
12
+ "version": "0.0.0-pr-749.sha-e9face1",
13
13
  "description": "The tempo-id CLI: sign in to Tempo ID, and call its API and the Admin API.",
14
14
  "type": "module",
15
15
  "bin": {