@tempoxyz/id 0.0.0-pr-718.sha-8b3b450 → 0.0.0-pr-723.sha-e2f626f

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,8 +4,8 @@ import {
4
4
  name,
5
5
  parseName,
6
6
  pending
7
- } from "./chunk-7JMEEUUA.js";
8
- import "./chunk-MTJSZT4S.js";
7
+ } from "./chunk-K4WPSEXZ.js";
8
+ import "./chunk-AOIGHDXR.js";
9
9
  import "./chunk-YW5DUQT3.js";
10
10
  import "./chunk-MLKGABMK.js";
11
11
  export {
@@ -4,7 +4,7 @@ import {
4
4
  machines,
5
5
  prompt,
6
6
  waiting
7
- } from "./chunk-MTJSZT4S.js";
7
+ } from "./chunk-AOIGHDXR.js";
8
8
  import "./chunk-MLKGABMK.js";
9
9
  export {
10
10
  create,
@@ -308,6 +308,7 @@ async function clientAuthentication(auth) {
308
308
  if (auth.clientSecret) return { client_secret: auth.clientSecret };
309
309
  return {};
310
310
  }
311
+ var revokeTimeout = 1e4;
311
312
  async function revoke(auth, options) {
312
313
  const body = new URLSearchParams({
313
314
  client_id: auth.clientId,
@@ -315,29 +316,38 @@ async function revoke(auth, options) {
315
316
  token_type_hint: "refresh_token",
316
317
  ...await clientAuthentication(auth)
317
318
  });
318
- const response = await (auth.fetch ?? fetch)(
319
- new URL("/oauth2/revoke", auth.url),
320
- {
321
- body,
322
- // A session cookie fails the issuer's origin check, and the revocation needs none.
323
- credentials: "omit",
324
- method: "POST",
325
- // A redirect would send the refresh token and the client authentication to another origin.
326
- redirect: "manual"
327
- }
328
- ).catch((error3) => {
329
- throw new RequestError({
330
- cause: error3,
331
- code: "server_error",
332
- message: "The revocation received no response. Check the connection, and sign out again.",
333
- status: 0
319
+ const controller = new AbortController();
320
+ const timer = setTimeout(() => controller.abort(), revokeTimeout);
321
+ try {
322
+ const response = await (auth.fetch ?? fetch)(
323
+ new URL("/oauth2/revoke", auth.url),
324
+ {
325
+ body,
326
+ // A session cookie fails the issuer's origin check, and the revocation needs none.
327
+ credentials: "omit",
328
+ method: "POST",
329
+ // A redirect would send the refresh token and the client authentication to another origin.
330
+ redirect: "manual",
331
+ signal: controller.signal
332
+ }
333
+ ).catch((error3) => {
334
+ if (controller.signal.aborted) return void 0;
335
+ throw new RequestError({
336
+ cause: error3,
337
+ code: "server_error",
338
+ message: "The revocation received no response. Check the connection, and sign out again.",
339
+ status: 0
340
+ });
334
341
  });
335
- });
336
- if (response.ok) {
337
- await response.body?.cancel();
338
- return;
342
+ if (!response) return;
343
+ if (response.ok) {
344
+ await response.body?.cancel();
345
+ return;
346
+ }
347
+ await json(response);
348
+ } finally {
349
+ clearTimeout(timer);
339
350
  }
340
- await json(response);
341
351
  }
342
352
  var clientAssertionType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
343
353
  async function tokenHeaders(auth, options) {
@@ -359,6 +369,16 @@ function requestHeaders(init, options) {
359
369
  function bound(token2) {
360
370
  return jkt(token2) !== void 0;
361
371
  }
372
+ function lifetime(token2) {
373
+ try {
374
+ const claims = JSON.parse(Base642.toString(token2.split(".")[1] ?? ""));
375
+ if (typeof claims.exp !== "number" || typeof claims.iat !== "number")
376
+ return void 0;
377
+ return (claims.exp - claims.iat) * 1e3;
378
+ } catch {
379
+ return void 0;
380
+ }
381
+ }
362
382
  function jkt(token2) {
363
383
  try {
364
384
  const claims = JSON.parse(Base642.toString(token2.split(".")[1] ?? ""));
@@ -1005,9 +1025,9 @@ async function authorizeUrl(auth, options) {
1005
1025
  if (!accessKey2 && options.challenge !== void 0)
1006
1026
  throw new ChallengeWithoutKeyError();
1007
1027
  const redirectUri = options.redirectUri ?? auth.redirectUri ?? `${window.location.origin}/`;
1008
- const key = accessKey2 ? await resolve(accessKey2) : void 0;
1028
+ const key = accessKey2 && !("address" in accessKey2) ? await resolve(accessKey2) : void 0;
1009
1029
  const pending = from2({
1010
- ...key ? key.material : { key: false },
1030
+ ...key ? key.material : accessKey2 ? {} : { key: false },
1011
1031
  chainId: auth.chainId,
1012
1032
  clientId: auth.clientId,
1013
1033
  redirectUri,
@@ -1015,9 +1035,13 @@ async function authorizeUrl(auth, options) {
1015
1035
  state: Base644.fromBytes(Bytes2.random(16), base64url),
1016
1036
  verifier: Base644.fromBytes(Bytes2.random(32), base64url)
1017
1037
  });
1018
- const authorization2 = key && accessKey2 ? keyAuthorization(auth, {
1019
- accessKey: { ...accessKey2, account: key.accessKey }
1020
- }) : void 0;
1038
+ const authorization2 = (() => {
1039
+ if (!accessKey2) return void 0;
1040
+ if ("address" in accessKey2) return keyAuthorization(auth, { accessKey: accessKey2 });
1041
+ return keyAuthorization(auth, {
1042
+ accessKey: { ...accessKey2, account: key.accessKey }
1043
+ });
1044
+ })();
1021
1045
  const url = new URL("/oauth2/authorize", auth.url);
1022
1046
  const parameters = new URLSearchParams({
1023
1047
  ...options.challenge === void 0 ? {} : { challenge: options.challenge },
@@ -1074,23 +1098,39 @@ function request(auth, options) {
1074
1098
  };
1075
1099
  }
1076
1100
  function keyAuthorization(auth, options) {
1077
- const { account: signer } = options.accessKey;
1078
- const permissions2 = resolve2(options.accessKey, {
1101
+ const { accessKey: accessKey2 } = options;
1102
+ const permissions2 = resolve2(accessKey2, {
1079
1103
  chainId: auth.chainId
1080
1104
  });
1081
- const account2 = options.account ?? (signer.accessKeyAddress ? signer.address : void 0);
1105
+ const named = (() => {
1106
+ if ("address" in accessKey2)
1107
+ return {
1108
+ account: options.account ?? accessKey2.access,
1109
+ address: accessKey2.address,
1110
+ keyType: accessKey2.type ?? "secp256k1",
1111
+ witness: accessKey2.witness
1112
+ };
1113
+ const { account: signer } = accessKey2;
1114
+ return {
1115
+ account: options.account ?? (signer.accessKeyAddress ? signer.address : void 0),
1116
+ address: signer.accessKeyAddress ?? signer.address,
1117
+ keyType: signer.keyType,
1118
+ witness: void 0
1119
+ };
1120
+ })();
1082
1121
  return {
1083
- ...account2 ? { account: account2 } : {},
1084
- address: signer.accessKeyAddress ?? signer.address,
1122
+ ...named.account ? { account: named.account } : {},
1123
+ address: named.address,
1085
1124
  chainId: Hex2.fromNumber(permissions2.chainId),
1086
1125
  expiry: permissions2.expiry,
1087
- keyType: signer.keyType,
1126
+ keyType: named.keyType,
1088
1127
  limits: permissions2.limits?.map(({ limit, period, token: token2 }) => ({
1089
1128
  limit: Hex2.fromNumber(limit),
1090
1129
  ...period ? { period } : {},
1091
1130
  token: token2
1092
1131
  })),
1093
- scopes: permissions2.scopes
1132
+ scopes: permissions2.scopes,
1133
+ ...named.witness ? { witness: named.witness } : {}
1094
1134
  };
1095
1135
  }
1096
1136
  function funding(options) {
@@ -1672,6 +1712,7 @@ var funding_exports = {};
1672
1712
  __export(funding_exports, {
1673
1713
  BlockedError: () => BlockedError,
1674
1714
  OriginError: () => OriginError,
1715
+ PageRequiredError: () => PageRequiredError,
1675
1716
  complete: () => complete2,
1676
1717
  open: () => open
1677
1718
  });
@@ -1691,6 +1732,14 @@ var OriginError = class extends Error {
1691
1732
  );
1692
1733
  }
1693
1734
  };
1735
+ var PageRequiredError = class extends Error {
1736
+ name = "Actions.funding.PageRequiredError";
1737
+ constructor() {
1738
+ super(
1739
+ "No browser window: the deposit page opens only from a page. On a server, pass `funding` to `accounts.backend.start`. In a CLI, pass it to `accounts.device.signIn`."
1740
+ );
1741
+ }
1742
+ };
1694
1743
  function complete2(auth, options = {}) {
1695
1744
  const own2 = options.url === void 0;
1696
1745
  const url = new URL(options.url ?? window.location.href);
@@ -1716,6 +1765,10 @@ function complete2(auth, options = {}) {
1716
1765
  }
1717
1766
  async function open(auth, options) {
1718
1767
  const { amount, currency, signal, token: token2 } = options;
1768
+ if (typeof options.address === "object")
1769
+ Promise.resolve(options.address).catch(() => void 0);
1770
+ signal?.throwIfAborted();
1771
+ if (typeof document === "undefined") throw new PageRequiredError();
1719
1772
  const mode = (() => {
1720
1773
  const value = options.mode ?? "frame";
1721
1774
  if (value !== "frame") return value;
@@ -1727,8 +1780,6 @@ async function open(auth, options) {
1727
1780
  return "popup";
1728
1781
  return value;
1729
1782
  })();
1730
- if (options.address instanceof Promise) options.address.catch(() => void 0);
1731
- signal?.throwIfAborted();
1732
1783
  const redirectUri = options.redirectUri ?? auth.redirectUri ?? `${window.location.origin}/`;
1733
1784
  const toUrl = (address2, entry = { mode }) => {
1734
1785
  const url = new URL(
@@ -1768,7 +1819,7 @@ async function open(auth, options) {
1768
1819
  throw new OriginError({ origin: window.location.origin, redirectUri });
1769
1820
  if (mode === "popup" && options.mode !== "popup" && !activated()) {
1770
1821
  const address2 = await abortable(read2(), { signal });
1771
- const Sheet = await import("./Sheet-II5IGP5J.js");
1822
+ const Sheet = await import("./Sheet-GQPH2MUR.js");
1772
1823
  return await new Promise((resolve3, reject) => {
1773
1824
  const abort = () => {
1774
1825
  close();
@@ -1819,7 +1870,7 @@ async function watch(auth, options) {
1819
1870
  try {
1820
1871
  return await new Promise(
1821
1872
  (resolve3, reject) => {
1822
- void import("./Sheet-II5IGP5J.js").then(
1873
+ void import("./Sheet-GQPH2MUR.js").then(
1823
1874
  (Sheet) => {
1824
1875
  if (settled) return;
1825
1876
  unblock = Sheet.waiting({
@@ -1884,7 +1935,7 @@ function parse(url, options) {
1884
1935
  async function frame(auth, options) {
1885
1936
  const { redirectUri, signal, toUrl } = options;
1886
1937
  const address2 = await abortable(options.address, { signal });
1887
- const Sheet = await import("./Sheet-II5IGP5J.js");
1938
+ const Sheet = await import("./Sheet-GQPH2MUR.js");
1888
1939
  signal?.throwIfAborted();
1889
1940
  let close;
1890
1941
  let abort;
@@ -2052,7 +2103,7 @@ function complete3(auth, options = {}) {
2052
2103
  removed
2053
2104
  ]);
2054
2105
  return finish({
2055
- accessKey: own(options.accessKey),
2106
+ accessKey: options.accessKey,
2056
2107
  body,
2057
2108
  pending: stored
2058
2109
  });
@@ -2065,7 +2116,7 @@ async function createUrl(auth, options = {}) {
2065
2116
  }
2066
2117
  async function handleCallback(auth, options) {
2067
2118
  return finish({
2068
- accessKey: own(options.accessKey),
2119
+ accessKey: options.accessKey,
2069
2120
  body: await redeem(auth, {
2070
2121
  pending: options.pending,
2071
2122
  url: new URL(options.url)
@@ -2094,7 +2145,7 @@ function handleResult(options) {
2094
2145
  status: 400
2095
2146
  });
2096
2147
  return finish({
2097
- accessKey: own(options.accessKey),
2148
+ accessKey: options.accessKey,
2098
2149
  body: authorization2,
2099
2150
  pending: options.pending
2100
2151
  });
@@ -2172,13 +2223,24 @@ function finish(options) {
2172
2223
  signedIn: true,
2173
2224
  status: 400
2174
2225
  });
2226
+ if (options.accessKey && "address" in options.accessKey) {
2227
+ const tokens3 = tokens(body);
2228
+ return {
2229
+ ...tokens3,
2230
+ key: from({
2231
+ account: body.account,
2232
+ keyAuthorization: body.key_authorization
2233
+ }),
2234
+ user: user(tokens3)
2235
+ };
2236
+ }
2175
2237
  return authorization(
2176
2238
  {
2177
2239
  account: body.account,
2178
2240
  key_authorization: body.key_authorization,
2179
2241
  tokens: body
2180
2242
  },
2181
- { accessKey: options.accessKey, material }
2243
+ { accessKey: own(options.accessKey), material }
2182
2244
  );
2183
2245
  }
2184
2246
  async function prefetch(auth) {
@@ -2204,16 +2266,28 @@ async function prefetch(auth) {
2204
2266
  return urls;
2205
2267
  }
2206
2268
  async function start(auth, options = {}) {
2207
- const { pending, url } = await createUrl(auth, options);
2208
2269
  const store2 = get2(auth.store);
2270
+ const [{ pending, url }, stored] = await Promise.all([
2271
+ createUrl(auth, options),
2272
+ (async () => store2.getItem(indexKey))()
2273
+ ]);
2274
+ const index = stored ?? [];
2209
2275
  const now = Date.now();
2210
2276
  const expiresAt = now + pendingLifetime;
2211
- const index = await store2.getItem(indexKey) ?? [];
2212
- const expired3 = index.filter((entry) => entry.expiresAt <= now);
2213
- const kept = index.filter((entry) => entry.expiresAt > now);
2277
+ const page = [
2278
+ ...(written.get(store2) ?? []).filter((entry) => entry.expiresAt > now),
2279
+ { expiresAt, state: pending.state }
2280
+ ];
2281
+ written.set(store2, page);
2282
+ const rows = [
2283
+ ...index,
2284
+ ...page.filter((entry) => !index.some((row) => row.state === entry.state))
2285
+ ];
2286
+ const expired3 = rows.filter((entry) => entry.expiresAt <= now);
2287
+ const kept = rows.filter((entry) => entry.expiresAt > now);
2214
2288
  await Promise.all([
2215
2289
  ...expired3.map((entry) => store2.removeItem(storeKey(entry.state))),
2216
- store2.setItem(indexKey, [...kept, { expiresAt, state: pending.state }], {
2290
+ store2.setItem(indexKey, kept, {
2217
2291
  expiresAt
2218
2292
  }),
2219
2293
  store2.setItem(storeKey(pending.state), pending, { expiresAt })
@@ -2222,6 +2296,7 @@ async function start(auth, options = {}) {
2222
2296
  window.location.assign(url);
2223
2297
  }
2224
2298
  var completed = /* @__PURE__ */ new WeakMap();
2299
+ var written = /* @__PURE__ */ new WeakMap();
2225
2300
  var indexKey = "tempo-id:redirects";
2226
2301
  var pendingLifetime = 60 * 60 * 1e3;
2227
2302
  var legacyStoreKey = "tempo-id:redirect";
@@ -2413,7 +2488,7 @@ async function authorize3(auth, options) {
2413
2488
  let broadcast;
2414
2489
  let name;
2415
2490
  let unwatch;
2416
- let written;
2491
+ let written2;
2417
2492
  let sheet = reused;
2418
2493
  try {
2419
2494
  const { pending, url: popupUrl } = await Promise.race([
@@ -2435,8 +2510,8 @@ async function authorize3(auth, options) {
2435
2510
  if (mode === "iframe")
2436
2511
  sheet ??= create2({ url: frameUrl(auth, { redirectUri }) });
2437
2512
  name = channel({ state: pending.state });
2438
- written = Promise.resolve(store2.setItem(name, true));
2439
- await Promise.race([written, aborted, closed, replaced]);
2513
+ written2 = Promise.resolve(store2.setItem(name, true));
2514
+ await Promise.race([written2, aborted, closed, replaced]);
2440
2515
  if (popup?.closed)
2441
2516
  throw new DOMException("The user closed the sign-in.", "AbortError");
2442
2517
  const listener = new BroadcastChannel(name);
@@ -2519,7 +2594,7 @@ async function authorize3(auth, options) {
2519
2594
  popup?.close();
2520
2595
  if (name) {
2521
2596
  const item = name;
2522
- void (written ?? Promise.resolve()).then(() => store2.removeItem(item)).catch(() => {
2597
+ void (written2 ?? Promise.resolve()).then(() => store2.removeItem(item)).catch(() => {
2523
2598
  });
2524
2599
  }
2525
2600
  }
@@ -2666,10 +2741,10 @@ __export(email_exports2, {
2666
2741
  import { Authentication as Authentication3 } from "ox/webauthn";
2667
2742
 
2668
2743
  // ../../accounts/src/internal/Registration.ts
2669
- var lifetime = 4 * 60 * 1e3;
2744
+ var lifetime2 = 4 * 60 * 1e3;
2670
2745
  function from3(value, options) {
2671
2746
  return {
2672
- expiresAt: options.requestedAt + lifetime,
2747
+ expiresAt: options.requestedAt + lifetime2,
2673
2748
  options: value.options,
2674
2749
  ...value.proof ? { proof: value.proof } : {}
2675
2750
  };
@@ -3315,9 +3390,10 @@ function create3(options) {
3315
3390
  // The message names a sign-out, which other tabs count as one. Another empty write,
3316
3391
  // such as a renewal of an expired session, empties their session as `set` does.
3317
3392
  save: (args) => {
3393
+ const signOut3 = args.event.type.startsWith("signOut");
3318
3394
  const message = {
3319
- everywhere: args.context.signingOut?.everywhere,
3320
- signOut: args.event.type.startsWith("signOut")
3395
+ everywhere: signOut3 && args.context.signingOut?.everywhere,
3396
+ signOut: signOut3
3321
3397
  };
3322
3398
  writes?.save(name, args.context.session).then(() => channel2?.postMessage(message)).catch(() => void 0);
3323
3399
  }
@@ -3325,11 +3401,13 @@ function create3(options) {
3325
3401
  })
3326
3402
  ).start() : void 0;
3327
3403
  let obtained = 0;
3404
+ let obtainedLogouts = 0;
3328
3405
  let held = actor?.getSnapshot().context.session;
3329
3406
  actor?.subscribe((snapshot) => {
3330
3407
  if (snapshot.context.session === held) return;
3331
3408
  held = snapshot.context.session;
3332
3409
  obtained = Date.now();
3410
+ obtainedLogouts = snapshot.context.logouts.remote;
3333
3411
  });
3334
3412
  const context = () => actor.getSnapshot().context;
3335
3413
  function set(session2, options2 = {}) {
@@ -3460,9 +3538,17 @@ function create3(options) {
3460
3538
  (entry) => typeof entry === "string"
3461
3539
  ) : [];
3462
3540
  },
3541
+ /**
3542
+ * Returns the tokens that the entry holds once the store took the write, at most the latest 16,
3543
+ * or `undefined` when the store refused it.
3544
+ */
3463
3545
  async write(tokens3) {
3464
3546
  const key = `${name}:unanswered`;
3465
- await (async () => tokens3.length === 0 ? store2?.removeItem(key) : store2?.setItem(key, tokens3.slice(-16)))().catch(() => void 0);
3547
+ const held2 = tokens3.slice(-16);
3548
+ return (async () => {
3549
+ await (held2.length === 0 ? store2?.removeItem(key) : store2?.setItem(key, held2));
3550
+ return held2;
3551
+ })().catch(() => void 0);
3466
3552
  }
3467
3553
  };
3468
3554
  const revoked = {
@@ -3673,6 +3759,7 @@ function create3(options) {
3673
3759
  return () => subscription.unsubscribe();
3674
3760
  }
3675
3761
  const rotated = /* @__PURE__ */ new Map();
3762
+ const retained = /* @__PURE__ */ new Map();
3676
3763
  const authorizations = /* @__PURE__ */ new Set();
3677
3764
  return {
3678
3765
  actor,
@@ -3938,19 +4025,41 @@ function create3(options) {
3938
4025
  await hydrate();
3939
4026
  await writes?.flush().catch(() => void 0);
3940
4027
  const local = actor ? context().session : void 0;
4028
+ const unsaved = !!local && writes?.unsaved() === local;
4029
+ const logouts = obtainedLogouts;
4030
+ const since = obtained;
3941
4031
  const before = await read2();
3942
4032
  actor?.send({ type: "signOut" });
3943
4033
  const ownSignIns = actor ? context().signIns : 0;
3944
4034
  rotated.clear();
3945
4035
  const emptied = settle(writes?.flush());
3946
4036
  return exclusive(async () => {
3947
- const [{ failed, stored }, earlier, digests] = await Promise.all([
3948
- emptied.then(async (failed2) => ({ failed: failed2, stored: await read2() })),
3949
- unanswered2.read(),
3950
- revoked.read()
3951
- ]);
4037
+ const [{ failed, stored }, earlier, digests, entries] = await Promise.all(
4038
+ [
4039
+ emptied.then(async (failed2) => ({ failed: failed2, stored: await read2() })),
4040
+ unanswered2.read(),
4041
+ revoked.read(),
4042
+ unsaved ? rotations.read() : void 0
4043
+ ]
4044
+ );
4045
+ const held2 = !before || !local || before.user.id !== local.user.id;
4046
+ const revocable = (token2) => machines2.revocable({
4047
+ entries,
4048
+ held: held2,
4049
+ live: token2 && entries ? rotations.successor(entries, token2) : void 0,
4050
+ remote: !!actor && context().logouts.remote !== logouts,
4051
+ revoked: options2.revoked,
4052
+ since,
4053
+ token: token2
4054
+ });
3952
4055
  const current = actor ? context().session : void 0;
3953
- const ending = machines2.ending({ before, current, local, stored });
4056
+ const ending = machines2.ending({
4057
+ before,
4058
+ current,
4059
+ failed: unsaved,
4060
+ local,
4061
+ stored
4062
+ });
3954
4063
  if (ending.empty)
3955
4064
  actor?.send({ type: current ? "save" : "signOut.empty" });
3956
4065
  const saved = ending.empty ? await settle(writes?.flush()) : void 0;
@@ -3959,11 +4068,24 @@ function create3(options) {
3959
4068
  const skipped = ended?.refreshToken ? rotated.get(ended.refreshToken) : void 0;
3960
4069
  const signIns = actor ? context().signIns : 0;
3961
4070
  const known = !!ended?.refreshToken && ended.refreshToken === options2.revoked;
3962
- const revoking = known || ended?.refreshToken && rotated.has(ended.refreshToken) || revoked.has(digests, ended) ? void 0 : ended;
3963
- const pending = (earlier ?? []).filter(
4071
+ const stale = unsaved && ended === local && !revocable(ended?.refreshToken);
4072
+ const revoking = known || stale || ended?.refreshToken && rotated.has(ended.refreshToken) || revoked.has(digests, ended) ? void 0 : ended;
4073
+ const unsavedToken = revocable(ending.unsaved?.refreshToken) ? ending.unsaved?.refreshToken : void 0;
4074
+ const resent = machines2.resent({
4075
+ remote: actor ? context().logouts.remote : void 0,
4076
+ retained
4077
+ });
4078
+ const pending = [
4079
+ .../* @__PURE__ */ new Set([
4080
+ ...earlier ?? [],
4081
+ ...resent,
4082
+ ...unsavedToken ? [unsavedToken] : []
4083
+ ])
4084
+ ].filter(
3964
4085
  (token2) => token2 !== revoking?.refreshToken && !revoked.has(digests, { refreshToken: token2 })
3965
4086
  );
3966
4087
  const answered2 = /* @__PURE__ */ new Set();
4088
+ const errors = /* @__PURE__ */ new Map();
3967
4089
  const signedOut = await settle(
3968
4090
  signOut2(revoking, {
3969
4091
  logout: machines2.logout({
@@ -3983,6 +4105,9 @@ function create3(options) {
3983
4105
  answered2.add(refreshToken);
3984
4106
  return Promise.resolve();
3985
4107
  },
4108
+ onUnanswered: (error3) => {
4109
+ errors.set(refreshToken, error3);
4110
+ },
3986
4111
  refreshToken
3987
4112
  })),
3988
4113
  unrevoked: skipped
@@ -3996,22 +4121,47 @@ function create3(options) {
3996
4121
  ...pending.filter((token2) => answered2.has(token2)),
3997
4122
  ...revoking?.refreshToken && answered2.has(revoking.refreshToken) ? [revoking.refreshToken] : []
3998
4123
  ];
3999
- await Promise.all([
4124
+ const [, persisted] = await Promise.all([
4000
4125
  revoked.write(digests, marks),
4001
4126
  (async () => {
4002
4127
  if (earlier === void 0) {
4003
4128
  const again = live.length > 0 ? await unanswered2.read() : void 0;
4004
- if (again)
4005
- await unanswered2.write([
4006
- ...again.filter((token2) => !live.includes(token2)),
4007
- ...live
4008
- ]);
4009
- } else if (earlier.length > 0 || live.length > 0)
4010
- await unanswered2.write(live);
4129
+ if (!again) return live.length === 0 ? [] : void 0;
4130
+ return unanswered2.write([
4131
+ ...again.filter((token2) => !live.includes(token2)),
4132
+ ...live
4133
+ ]);
4134
+ }
4135
+ if (earlier.length > 0 || live.length > 0)
4136
+ return unanswered2.write(live);
4137
+ return [];
4011
4138
  })()
4012
4139
  ]);
4140
+ const kept = machines2.retains({
4141
+ live,
4142
+ logouts,
4143
+ persisted,
4144
+ retained,
4145
+ unsaved: [
4146
+ ...unsavedToken ? [unsavedToken] : [],
4147
+ ...unsaved && local?.refreshToken ? [local.refreshToken] : []
4148
+ ]
4149
+ });
4150
+ retained.clear();
4151
+ for (const [token2, remote] of kept) retained.set(token2, remote);
4013
4152
  if (erased) throw erased.error;
4014
4153
  if (signedOut) throw signedOut.error;
4154
+ const unsent = [...unsavedToken ? [unsavedToken] : [], ...resent];
4155
+ const failing = unsent.find(
4156
+ (token2) => pending.includes(token2) && !answered2.has(token2)
4157
+ );
4158
+ if (failing && errors.has(failing)) throw errors.get(failing);
4159
+ if (failing)
4160
+ throw new RequestError({
4161
+ code: "server_error",
4162
+ message: "Revocation failed: no response for the refresh token of the unsaved session. Sign out again once online.",
4163
+ status: 0
4164
+ });
4015
4165
  });
4016
4166
  }
4017
4167
  }
@@ -4042,13 +4192,16 @@ function settle(promise) {
4042
4192
  function queue(store2, options = {}) {
4043
4193
  let pending = Promise.resolve();
4044
4194
  let failed = false;
4045
- const enqueue = (write) => {
4195
+ let unsaved;
4196
+ const enqueue = (write, session2) => {
4046
4197
  const next = pending.catch(() => void 0).then(write).then(
4047
4198
  () => {
4048
4199
  failed = false;
4200
+ unsaved = void 0;
4049
4201
  },
4050
4202
  (error3) => {
4051
4203
  failed = true;
4204
+ unsaved = session2;
4052
4205
  throw error3;
4053
4206
  }
4054
4207
  );
@@ -4065,6 +4218,8 @@ function queue(store2, options = {}) {
4065
4218
  };
4066
4219
  return {
4067
4220
  failed: () => failed,
4221
+ /** Returns the session that the last write failed to save, or `undefined` after a saved write. */
4222
+ unsaved: () => unsaved,
4068
4223
  /**
4069
4224
  * Resolves when every earlier write completed. It reads the queue after a microtask, since a
4070
4225
  * change that a subscriber sends during another change is processed only once that change's
@@ -4079,7 +4234,8 @@ function queue(store2, options = {}) {
4079
4234
  () => store2.setItem(name, {
4080
4235
  state: { session: toSaved(session2) },
4081
4236
  version: 0
4082
- })
4237
+ }),
4238
+ session2
4083
4239
  ),
4084
4240
  storage
4085
4241
  };
@@ -4163,6 +4319,7 @@ var machines2;
4163
4319
  logout: assign2((args) => ({
4164
4320
  logouts: {
4165
4321
  ...args.context.logouts,
4322
+ remote: args.context.logouts.remote + 1,
4166
4323
  started: args.context.logouts.started + 1
4167
4324
  }
4168
4325
  })),
@@ -4199,7 +4356,11 @@ var machines2;
4199
4356
  const { logouts, signingOut } = args.context;
4200
4357
  const { everywhere } = args.event;
4201
4358
  return {
4202
- logouts: everywhere ? { running: logouts.running + 1, started: logouts.started + 1 } : logouts,
4359
+ logouts: everywhere ? {
4360
+ ...logouts,
4361
+ running: logouts.running + 1,
4362
+ started: logouts.started + 1
4363
+ } : logouts,
4203
4364
  marked: !everywhere,
4204
4365
  signingOut: { everywhere, runs: (signingOut?.runs ?? 0) + 1 }
4205
4366
  };
@@ -4240,7 +4401,7 @@ var machines2;
4240
4401
  authorizations: 0,
4241
4402
  delegations: 0,
4242
4403
  loaded: false,
4243
- logouts: { running: 0, started: 0 },
4404
+ logouts: { remote: 0, running: 0, started: 0 },
4244
4405
  marked: false,
4245
4406
  refusals: 0,
4246
4407
  renewing: void 0,
@@ -4298,17 +4459,24 @@ var machines2;
4298
4459
  }
4299
4460
  machines4.adoptable = adoptable;
4300
4461
  function ending(options) {
4301
- const { before, current, local, stored } = options;
4302
- const ended2 = machines4.newer(before, local) ? before : local;
4303
- if (!stored || !ended2) return { empty: false, kept: false, session: ended2 };
4462
+ const { before, current, failed, local, stored } = options;
4463
+ const ended2 = (() => {
4464
+ if (failed && !before) return local;
4465
+ return machines4.newer(before, local) ? before : local;
4466
+ })();
4467
+ const unsaved = failed && before && local && before.user.id !== local.user.id ? local : void 0;
4468
+ if (!stored || !ended2)
4469
+ return { empty: false, kept: false, session: ended2, unsaved };
4470
+ const held = !(failed && !before);
4304
4471
  const own2 = stored.refreshToken === current?.refreshToken;
4305
- const later = !own2 && stored.user.id === ended2.user.id && stored.key?.keyAuthorization.keyId === ended2.key?.keyAuthorization.keyId && stored.refreshToken !== ended2.refreshToken && stored.expiresAt >= ended2.expiresAt;
4306
- const stale = !own2 && stored.refreshToken === ended2.refreshToken;
4472
+ const later = held && !own2 && stored.user.id === ended2.user.id && stored.key?.keyAuthorization.keyId === ended2.key?.keyAuthorization.keyId && stored.refreshToken !== ended2.refreshToken && stored.expiresAt >= ended2.expiresAt;
4473
+ const stale = held && !own2 && stored.refreshToken === ended2.refreshToken;
4307
4474
  const kept = !own2 && !later && !stale && stored.user.id !== ended2.user.id;
4308
4475
  return {
4309
4476
  empty: later || stale,
4310
4477
  kept,
4311
- session: later ? stored : ended2
4478
+ session: later ? stored : ended2,
4479
+ unsaved
4312
4480
  };
4313
4481
  }
4314
4482
  machines4.ending = ending;
@@ -4327,6 +4495,32 @@ var machines2;
4327
4495
  return first.at > since - 1e3;
4328
4496
  }
4329
4497
  machines4.lacks = lacks;
4498
+ function resent(options) {
4499
+ const { remote, retained } = options;
4500
+ return [...retained].filter(([, entered]) => remote === void 0 || remote === entered).map(([token2]) => token2);
4501
+ }
4502
+ machines4.resent = resent;
4503
+ function retains(options) {
4504
+ const { live, logouts, persisted, retained, unsaved } = options;
4505
+ const result = /* @__PURE__ */ new Map();
4506
+ for (const token2 of live) {
4507
+ if (persisted?.includes(token2)) continue;
4508
+ const entered = retained.get(token2);
4509
+ if (entered !== void 0) result.set(token2, entered);
4510
+ else if (unsaved.includes(token2)) result.set(token2, logouts);
4511
+ }
4512
+ return result;
4513
+ }
4514
+ machines4.retains = retains;
4515
+ function revocable(options) {
4516
+ const { entries, held, live, remote, revoked, since, token: token2 } = options;
4517
+ if (!token2 || token2 === revoked) return false;
4518
+ if (remote) return false;
4519
+ if (!held) return true;
4520
+ if (!entries || machines4.lacks({ entries, since })) return false;
4521
+ return live === token2;
4522
+ }
4523
+ machines4.revocable = revocable;
4330
4524
  function loggedOut(options) {
4331
4525
  const { current, started } = options;
4332
4526
  if (current.logouts.started !== started.logouts.started) return true;
@@ -4418,11 +4612,13 @@ var machines2;
4418
4612
  }
4419
4613
  machines4.declined = declined;
4420
4614
  function rotated(options) {
4421
- const { current, now, started } = options;
4422
- if (!started?.refreshToken) return false;
4423
- if (current.user.id !== started.user.id) return false;
4615
+ const { current, lifetime: lifetime3, now, started, startedAt } = options;
4616
+ if (started && !started.refreshToken) return false;
4617
+ if (started && current.user.id !== started.user.id) return false;
4424
4618
  if (current.expiresAt <= now) return false;
4425
- return current.refreshToken !== started.refreshToken;
4619
+ if (lifetime3 === void 0) return false;
4620
+ if (current.expiresAt - lifetime3 <= startedAt) return false;
4621
+ return current.refreshToken !== started?.refreshToken;
4426
4622
  }
4427
4623
  machines4.rotated = rotated;
4428
4624
  function switches(options) {
@@ -4506,13 +4702,11 @@ async function run(context, parameters) {
4506
4702
  }
4507
4703
  function refresh3(context, options = {}) {
4508
4704
  const { margin } = options;
4509
- const started = margin === void 0 ? context.session.reload().catch(() => void 0) : void 0;
4705
+ const started = context.session.get();
4706
+ const startedAt = Date.now();
4510
4707
  return context.session.exclusive(async () => {
4511
4708
  await context.session.load({ locked: true });
4512
- const [current, before] = await Promise.all([
4513
- context.session.reload(),
4514
- started
4515
- ]);
4709
+ const current = await context.session.reload();
4516
4710
  const refreshToken = current?.refreshToken;
4517
4711
  if (!current || !refreshToken) return void 0;
4518
4712
  checkBound(context.config, { accessToken: current.accessToken });
@@ -4520,10 +4714,12 @@ function refresh3(context, options = {}) {
4520
4714
  await context.session.change({ update: true }).commit(current);
4521
4715
  return context.session.get();
4522
4716
  }
4523
- if (machines2.rotated({
4717
+ if (margin === void 0 && machines2.rotated({
4524
4718
  current,
4719
+ lifetime: lifetime(current.accessToken),
4525
4720
  now: Date.now(),
4526
- started: before
4721
+ started,
4722
+ startedAt
4527
4723
  })) {
4528
4724
  await context.session.change({ update: true }).commit(current);
4529
4725
  return context.session.get();
@@ -4712,7 +4908,7 @@ var signInIds = /* @__PURE__ */ new Set([
4712
4908
  function plugin() {
4713
4909
  let loading;
4714
4910
  function load() {
4715
- loading ??= import("./dialog-FFLTODHO.js").then((module) => module.dialog()).catch((error3) => {
4911
+ loading ??= import("./dialog-TGNSW7U4.js").then((module) => module.dialog()).catch((error3) => {
4716
4912
  loading = void 0;
4717
4913
  throw error3;
4718
4914
  });
@@ -5026,7 +5222,15 @@ function create4(options = {}) {
5026
5222
  return void 0;
5027
5223
  return revoke2(ended.refreshToken, onRevoked);
5028
5224
  })(),
5029
- ...pending.map((entry) => revoke2(entry.refreshToken, entry.onRevoked))
5225
+ ...pending.map(async (entry) => {
5226
+ const result = await revoke2(entry.refreshToken, entry.onRevoked);
5227
+ if (result) {
5228
+ if (typeof result.error === "object" && result.error)
5229
+ unanswered2.add(result.error);
5230
+ entry.onUnanswered?.(result.error);
5231
+ }
5232
+ return void 0;
5233
+ })
5030
5234
  ]);
5031
5235
  const loggedOut = logout && !thirdParty(config.clientId);
5032
5236
  if (loggedOut) {
@@ -5079,6 +5283,7 @@ function create4(options = {}) {
5079
5283
  plugin2.setup?.(context);
5080
5284
  }
5081
5285
  let refreshing;
5286
+ let rotating;
5082
5287
  async function ownAccessToken() {
5083
5288
  if (typeof document !== "undefined" || "WorkerGlobalScope" in globalThis)
5084
5289
  return void 0;
@@ -5116,7 +5321,7 @@ function create4(options = {}) {
5116
5321
  function connections2() {
5117
5322
  if (!connectionsOptions)
5118
5323
  return Promise.reject(new ConnectionsRequiredError());
5119
- attached ??= import("./Connections-DLVOXLEL.js").then(
5324
+ attached ??= import("./Connections-GTESLWTN.js").then(
5120
5325
  (module) => module.attach(config, connectionsOptions)
5121
5326
  );
5122
5327
  return attached;
@@ -5202,7 +5407,9 @@ function create4(options = {}) {
5202
5407
  },
5203
5408
  signedOut: session2.signedOut
5204
5409
  }),
5205
- refresh: () => refresh3(context),
5410
+ refresh: () => rotating ??= refresh3(context).finally(() => {
5411
+ rotating = void 0;
5412
+ }),
5206
5413
  status: session2.status,
5207
5414
  subscribe: session2.subscribe
5208
5415
  },
@@ -2,7 +2,7 @@ import {
2
2
  AccessKey_exports,
3
3
  Accounts_exports,
4
4
  Actions_exports
5
- } from "./chunk-MTJSZT4S.js";
5
+ } from "./chunk-AOIGHDXR.js";
6
6
 
7
7
  // src/Session.ts
8
8
  import * as Fs from "node:fs/promises";
@@ -5,7 +5,7 @@ import {
5
5
  expired,
6
6
  from,
7
7
  revokeAccessKey
8
- } from "./chunk-MTJSZT4S.js";
8
+ } from "./chunk-AOIGHDXR.js";
9
9
  import {
10
10
  from as from2
11
11
  } from "./chunk-YW5DUQT3.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  env,
3
3
  login
4
- } from "../chunk-O3UAZSAM.js";
5
- import "../chunk-7JMEEUUA.js";
6
- import "../chunk-MTJSZT4S.js";
4
+ } from "../chunk-DN57D5UC.js";
5
+ import "../chunk-K4WPSEXZ.js";
6
+ import "../chunk-AOIGHDXR.js";
7
7
  import "../chunk-YW5DUQT3.js";
8
8
  import "../chunk-MLKGABMK.js";
9
9
 
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  env,
3
3
  remove
4
- } from "../chunk-O3UAZSAM.js";
5
- import "../chunk-7JMEEUUA.js";
6
- import "../chunk-MTJSZT4S.js";
4
+ } from "../chunk-DN57D5UC.js";
5
+ import "../chunk-K4WPSEXZ.js";
6
+ import "../chunk-AOIGHDXR.js";
7
7
  import "../chunk-YW5DUQT3.js";
8
8
  import "../chunk-MLKGABMK.js";
9
9
 
@@ -2,9 +2,9 @@ import {
2
2
  env,
3
3
  signedOut,
4
4
  whoami
5
- } from "../chunk-O3UAZSAM.js";
6
- import "../chunk-7JMEEUUA.js";
7
- import "../chunk-MTJSZT4S.js";
5
+ } from "../chunk-DN57D5UC.js";
6
+ import "../chunk-K4WPSEXZ.js";
7
+ import "../chunk-AOIGHDXR.js";
8
8
  import "../chunk-YW5DUQT3.js";
9
9
  import "../chunk-MLKGABMK.js";
10
10
 
@@ -4,7 +4,7 @@ import {
4
4
  expired2 as expired,
5
5
  from2 as from,
6
6
  toSession
7
- } from "./chunk-MTJSZT4S.js";
7
+ } from "./chunk-AOIGHDXR.js";
8
8
  import "./chunk-MLKGABMK.js";
9
9
 
10
10
  // ../../accounts/src/plugins/dialog.ts
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-718.sha-8b3b450",
12
+ "version": "0.0.0-pr-723.sha-e2f626f",
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": {