@ai-matrx/vault 0.1.55 → 0.1.57

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.cjs CHANGED
@@ -2621,10 +2621,22 @@ function TotpRow({ port, item, onChanged }) {
2621
2621
  function TotpEditRow({ value, onChange, hasExisting, item, port, onEnrolled, onRecognized }) {
2622
2622
  const confirmed = useConfirmed();
2623
2623
  const [status, setStatus] = (0, import_react12.useState)(null);
2624
+ const [retryImage, setRetryImage] = (0, import_react12.useState)(null);
2625
+ const latestItem = (0, import_react12.useRef)(item);
2626
+ latestItem.current = item;
2624
2627
  const uploadImage = item && port ? async (file) => {
2628
+ setRetryImage(file);
2625
2629
  setStatus("Adding from image\u2026");
2626
2630
  try {
2627
- const entry = await confirmed(() => port.authenticator.enrolQrImage(item, file, file.name));
2631
+ const entry = await confirmed(async () => {
2632
+ const current = await port.get(item);
2633
+ const visible = latestItem.current;
2634
+ if (!visible || visible.id !== item.id || visible.authenticatorState !== "known" || current.authenticatorState !== "known" || !item.authenticator && (visible.authenticator || current.authenticator)) {
2635
+ throw new Error("Authenticator status unavailable. Retry after refreshing.");
2636
+ }
2637
+ return port.authenticator.enrolQrImage(current, file, file.name);
2638
+ });
2639
+ setRetryImage(null);
2628
2640
  setStatus(entry.issuer ? `Added \xB7 ${entry.issuer}` : "Added");
2629
2641
  onChange("");
2630
2642
  onEnrolled?.({ ...item, authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } });
@@ -2641,7 +2653,11 @@ function TotpEditRow({ value, onChange, hasExisting, item, port, onEnrolled, onR
2641
2653
  onChange(v);
2642
2654
  },
2643
2655
  placeholder: hasExisting ? "Paste a new key to replace" : SETUP_KEY_PLACEHOLDER,
2644
- status,
2656
+ status: status && retryImage && uploadImage ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2657
+ status,
2658
+ " ",
2659
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_controls8.Button, { variant: "quiet", onClick: () => void uploadImage(retryImage), children: "Retry" })
2660
+ ] }) : status,
2645
2661
  ...uploadImage ? { onImage: (f) => void uploadImage(f) } : {},
2646
2662
  ...onRecognized ? { onRecognized } : {}
2647
2663
  }
@@ -2702,7 +2718,9 @@ function normalizeWebsite(raw) {
2702
2718
  }
2703
2719
  function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onAdded, onDone }) {
2704
2720
  const confirmed = useConfirmed();
2705
- const candidates = items.filter((i) => !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
2721
+ const itemsRef = (0, import_react13.useRef)(items);
2722
+ itemsRef.current = items;
2723
+ const candidates = items.filter((i) => i.authenticatorState === "known" && !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
2706
2724
  const [input, setInput] = (0, import_react13.useState)("");
2707
2725
  const [image, setImage] = (0, import_react13.useState)(null);
2708
2726
  const [target, setTarget] = (0, import_react13.useState)(itemId && candidates.some((c) => c.id === itemId) ? itemId : NEW);
@@ -2730,18 +2748,26 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2730
2748
  setBusy(true);
2731
2749
  setError(null);
2732
2750
  try {
2733
- let item = isNew ? created : items.find((i) => i.id === target) ?? null;
2751
+ let item = isNew ? created : itemsRef.current.find((i) => i.id === target) ?? null;
2752
+ let freshlyCreated = false;
2753
+ if (!isNew && (!item || item.authenticatorState !== "known" || item.authenticator)) throw new Error("Authenticator status unavailable. Retry after refreshing.");
2734
2754
  if (!item) {
2735
2755
  const def = LOGIN_KEYS.map((k) => definitions.find((d) => d.key === k)).find((d) => Boolean(d));
2736
2756
  if (!def) throw new Error("No login type is available.");
2737
2757
  const r = await port.create(def, null, { ...draftOf(null), name: name.trim(), loginUrls: websiteUrl ? [websiteUrl] : [] });
2738
2758
  item = r.item;
2759
+ freshlyCreated = true;
2739
2760
  setCreated(item);
2740
2761
  onChanged();
2741
2762
  }
2742
2763
  const it = item;
2743
- const entry = await confirmed(() => image ? port.authenticator.enrolQrImage(it, image, image.name) : port.authenticator.enrol(it, input));
2744
- let next = { ...it, authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
2764
+ const entry = await confirmed(async () => {
2765
+ const latest = freshlyCreated ? it : await port.get(it);
2766
+ const listed = itemsRef.current.find((i) => i.id === it.id);
2767
+ if (!freshlyCreated && (latest.authenticatorState !== "known" || latest.authenticator || !isNew && !listed) || listed && (listed.authenticatorState !== "known" || listed.authenticator)) throw new Error("Authenticator status unavailable. Retry after refreshing.");
2768
+ return image ? port.authenticator.enrolQrImage(latest, image, image.name) : port.authenticator.enrol(latest, input);
2769
+ });
2770
+ let next = { ...it, authenticatorState: "known", authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
2745
2771
  const better = authenticatorName(it.name, { issuer: entry.issuer, account: entry.account });
2746
2772
  if (!isNew && better !== it.name) {
2747
2773
  try {
@@ -2827,7 +2853,11 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2827
2853
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VaultRow, { label: "Website", hint: websiteBad ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-destructive", children: "Not a web address" }) : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Field, { className: "w-full", type: "url", value: website, disabled: busy || created !== null, onChange: (e) => setWebsite(e.target.value), placeholder: "example.com", "aria-label": "Website", "aria-invalid": websiteBad || void 0 }) })
2828
2854
  ] }) : null
2829
2855
  ] }),
2830
- error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "px-1 text-sm text-destructive", role: "alert", children: error }) : null
2856
+ error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "px-1 text-sm text-destructive", role: "alert", children: [
2857
+ error,
2858
+ " ",
2859
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
2860
+ ] }) : null
2831
2861
  ]
2832
2862
  }
2833
2863
  );
@@ -2862,23 +2892,8 @@ function otpGroups(items, entries, query, hidden = /* @__PURE__ */ new Set()) {
2862
2892
  const rank = (k) => k === "me" ? 0 : k === "shared" ? 2 : 1;
2863
2893
  return [...groups.entries()].sort(([a, x], [b, y]) => rank(a) - rank(b) || x.label.localeCompare(y.label)).map(([key, g]) => ({ key, ...g }));
2864
2894
  }
2865
- function withAdded(items, added) {
2866
- if (added.size === 0) return items;
2867
- const seen = /* @__PURE__ */ new Set();
2868
- const out = items.map((i) => {
2869
- seen.add(i.id);
2870
- const mine = added.get(i.id);
2871
- return mine && !i.authenticator ? { ...i, authenticator: mine.authenticator, name: mine.name } : i;
2872
- });
2873
- for (const [id, a] of added) if (!seen.has(id)) out.push(a);
2874
- return out;
2875
- }
2876
- function AuthenticatorView({ port, host, items: listed, definitions, query, onOpen, onChanged, header }) {
2877
- const [added, setAdded] = (0, import_react14.useState)(/* @__PURE__ */ new Map());
2878
- const items = withAdded(listed, added);
2879
- (0, import_react14.useEffect)(() => {
2880
- if (added.size > 0 && [...added.keys()].every((id) => listed.some((i) => i.id === id && i.authenticator))) setAdded(/* @__PURE__ */ new Map());
2881
- }, [listed, added]);
2895
+ function AuthenticatorView({ port, host, items, definitions, query, onOpen, onChanged, header }) {
2896
+ const [incomplete, setIncomplete] = (0, import_react14.useState)(true);
2882
2897
  const [entries, setEntries] = (0, import_react14.useState)(/* @__PURE__ */ new Map());
2883
2898
  const [hidden, setHidden] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
2884
2899
  const [adding, setAdding] = (0, import_react14.useState)(false);
@@ -2888,13 +2903,20 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
2888
2903
  (0, import_react14.useEffect)(() => {
2889
2904
  let live = true;
2890
2905
  port.authenticator.list().then(
2891
- (list) => live && setEntries(new Map(list.map((e) => [e.itemId, e]))),
2892
- (e) => console.error("One-time password accounts could not be read", e)
2906
+ (list) => {
2907
+ if (live) {
2908
+ setEntries(new Map(list.entries.map((e) => [e.itemId, e])));
2909
+ setIncomplete(list.unavailableScopes.length > 0);
2910
+ }
2911
+ },
2912
+ () => {
2913
+ if (live) setIncomplete(true);
2914
+ }
2893
2915
  );
2894
2916
  return () => {
2895
2917
  live = false;
2896
2918
  };
2897
- }, [port, listed, added]);
2919
+ }, [port, items]);
2898
2920
  const groups = otpGroups(items, entries, query, hidden);
2899
2921
  const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
2900
2922
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -2907,7 +2929,14 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
2907
2929
  ] }),
2908
2930
  total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
2909
2931
  ] }),
2910
- total === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
2932
+ total > 0 && (incomplete || items.some((i) => i.authenticatorState !== "known")) ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-4 text-sm text-muted-foreground", children: [
2933
+ "Some codes unavailable ",
2934
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
2935
+ ] }) : null,
2936
+ total === 0 && (incomplete || items.some((i) => i.authenticatorState !== "known")) ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: [
2937
+ "Codes unavailable ",
2938
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
2939
+ ] }) : total === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
2911
2940
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ShieldGlyph, { className: "size-6" }) }),
2912
2941
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
2913
2942
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
@@ -2940,7 +2969,6 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
2940
2969
  definitions,
2941
2970
  onClose: () => setAdding(false),
2942
2971
  onChanged,
2943
- onAdded: (item) => setAdded((cur) => new Map(cur).set(item.id, item)),
2944
2972
  onDone: (id) => {
2945
2973
  setAdding(false);
2946
2974
  onOpen(id);
@@ -6545,6 +6573,10 @@ function confirmDelete(item) {
6545
6573
  function ItemPane(props) {
6546
6574
  const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
6547
6575
  const confirmed = useConfirmed();
6576
+ const latestItem = (0, import_react30.useRef)(item);
6577
+ latestItem.current = item;
6578
+ const [createdForRetry, setCreatedForRetry] = (0, import_react30.useState)(null);
6579
+ const enrolledForRetry = (0, import_react30.useRef)(null);
6548
6580
  const notify = useNotify();
6549
6581
  const editing = mode !== "view";
6550
6582
  const seedName = seed?.name ?? "";
@@ -6630,23 +6662,39 @@ function ItemPane(props) {
6630
6662
  setError(null);
6631
6663
  const out = { ...draft, values: Object.fromEntries(changedValues(base, draft)) };
6632
6664
  if (out.values[RECOVERY_CODES_KEY] !== void 0) out.values[RECOVERY_CODES_KEY] = parseRecoveryCodes(out.values[RECOVERY_CODES_KEY]).join("\n");
6633
- const withOtp = async (saved, notice2) => {
6665
+ const withOtp = async (saved, notice2, freshlyCreated = false) => {
6634
6666
  const setup = out.authenticator.trim();
6635
6667
  if (!setup) return [saved, notice2, false];
6636
6668
  try {
6637
- await confirmed(() => port.authenticator.enrol(saved, setup));
6669
+ if (enrolledForRetry.current?.itemId !== saved.id || enrolledForRetry.current.setup !== setup) await confirmed(async () => {
6670
+ const current = freshlyCreated ? saved : await port.get(saved);
6671
+ const visible = latestItem.current?.id === saved.id ? latestItem.current : null;
6672
+ const ownEnrollment = enrolledForRetry.current?.itemId === saved.id;
6673
+ if (!freshlyCreated && (current.authenticatorState !== "known" || !item?.authenticator && current.authenticator && !ownEnrollment || item && !visible) || visible && (visible.authenticatorState !== "known" || !item?.authenticator && visible.authenticator && !ownEnrollment)) throw new Error("Authenticator status unavailable. Retry after refreshing");
6674
+ await port.authenticator.enrol(current, setup);
6675
+ enrolledForRetry.current = { itemId: saved.id, setup };
6676
+ });
6638
6677
  return [await port.get(saved), notice2, true];
6639
6678
  } catch (e) {
6679
+ if (enrolledForRetry.current?.itemId === saved.id && enrolledForRetry.current.setup === setup) return [saved, `Saved and authenticator set up, but refresh failed: ${e instanceof Error ? e.message : "Retry"}.`, false];
6640
6680
  const why = wasCancelled(e) ? "it was not confirmed" : e instanceof Error ? e.message : "it was refused";
6641
6681
  return [saved, `Saved, but the authenticator was not set up: ${why}. Add it with Edit.`, false];
6642
6682
  }
6643
6683
  };
6644
6684
  try {
6645
- if (item) {
6646
- const r = await port.save(item, definition, out);
6685
+ if (item || createdForRetry) {
6686
+ const r = await port.save(item ?? createdForRetry, definition, out);
6647
6687
  const [next, n, enrolled] = await withOtp(r.item, r.notice);
6648
- (0, import_drafts.dropKeptDraft)(keepKey);
6649
- onSaved(next, false, n, enrolled);
6688
+ if (out.authenticator.trim() && !enrolled) {
6689
+ setError(n);
6690
+ onChanged();
6691
+ return;
6692
+ }
6693
+ if (createdForRetry) await finishNew(next, n, enrolled);
6694
+ else {
6695
+ (0, import_drafts.dropKeptDraft)(keepKey);
6696
+ onSaved(next, false, n, enrolled);
6697
+ }
6650
6698
  } else if (definition && owner === "person") {
6651
6699
  const secretKey = declared.find((f) => f.storage === "encrypted" && f.kind === "secret")?.key ?? null;
6652
6700
  const r = await port.sharing.assign({ recipientEmail: recipient.trim(), definition, draft: out, generateFieldKey: generatePrivately ? secretKey : null });
@@ -6656,12 +6704,14 @@ function ItemPane(props) {
6656
6704
  setSent(r);
6657
6705
  } else if (definition) {
6658
6706
  const r = await port.create(definition, owner === "me" ? null : owner, out);
6659
- const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
6660
- const [next, n] = await storeQueuedFiles(withCode, n0);
6661
- (0, import_drafts.dropKeptDraft)(keepKey);
6662
- setSavedNew(true);
6663
- onDirty(false);
6664
- onSaved(next, true, n, enrolled);
6707
+ setCreatedForRetry(r.item);
6708
+ const [withCode, n0, enrolled] = await withOtp(r.item, r.notice, true);
6709
+ if (out.authenticator.trim() && !enrolled) {
6710
+ setError(n0);
6711
+ onChanged();
6712
+ return;
6713
+ }
6714
+ await finishNew(withCode, n0, enrolled);
6665
6715
  }
6666
6716
  } catch (e) {
6667
6717
  setError(e instanceof Error ? e.message : "Saving failed. Nothing was changed.");
@@ -6669,6 +6719,13 @@ function ItemPane(props) {
6669
6719
  setBusy(false);
6670
6720
  }
6671
6721
  }
6722
+ async function finishNew(saved, notice2, enrolled) {
6723
+ const [next, finalNotice] = await storeQueuedFiles(saved, notice2);
6724
+ (0, import_drafts.dropKeptDraft)(keepKey);
6725
+ setSavedNew(true);
6726
+ onDirty(false);
6727
+ onSaved(next, true, finalNotice, enrolled);
6728
+ }
6672
6729
  async function storeQueuedFiles(saved, notice2) {
6673
6730
  let next = saved;
6674
6731
  const failed = [];
@@ -6850,7 +6907,11 @@ function ItemPane(props) {
6850
6907
  const filesProps = item ? { item, port, host, definition, organizations, arg: null, onClose: () => void 0, onChanged, onPanel } : null;
6851
6908
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RoomProvider, { value: room, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("article", { ref: paneRef, "aria-label": item?.name ?? "New item", className: (0, import_design_system19.cn)(import_controls23.CONTROLS_CONTAINER_CLASS, "flex h-full min-h-0 flex-col bg-background"), children: [
6852
6909
  header,
6853
- error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
6910
+ error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: [
6911
+ error,
6912
+ " ",
6913
+ error.includes("Retry after refreshing") ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged(), children: "Retry" }) : null
6914
+ ] }) : null,
6854
6915
  notice && !editing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
6855
6916
  item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
6856
6917
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 0 ? "This item is turned off" : offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
@@ -6954,7 +7015,11 @@ function ItemPane(props) {
6954
7015
  i
6955
7016
  )),
6956
7017
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
6957
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
7018
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { hidden: Boolean(item && item.authenticatorState !== "known"), children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }) }),
7019
+ item && item.authenticatorState !== "known" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(VaultRow, { label: "Authenticator", children: [
7020
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
7021
+ item.authenticatorState === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
7022
+ ] }) : null,
6958
7023
  item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null,
6959
7024
  !item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
6960
7025
  recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -7033,7 +7098,10 @@ function ItemPane(props) {
7033
7098
  }),
7034
7099
  extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
7035
7100
  item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
7036
- item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
7101
+ item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpRow, { port, item, onChanged }) : item.authenticatorState !== "known" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(VaultRow, { label: "Authenticator", children: [
7102
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
7103
+ item.authenticatorState === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
7104
+ ] }) : seedField && !seedField.active ? (
7037
7105
  // The secret is still there, only off: turning it on brings the codes back. Never "Set up",
7038
7106
  // which would invite replacing a working two-factor secret.
7039
7107
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) })
@@ -9204,6 +9272,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
9204
9272
  const [refreshing, setRefreshing] = (0, import_react44.useState)(false);
9205
9273
  const loadedAt = (0, import_react44.useRef)(0);
9206
9274
  const inFlight = (0, import_react44.useRef)(false);
9275
+ const loadGeneration = (0, import_react44.useRef)(0);
9207
9276
  const apply = (0, import_react44.useCallback)(
9208
9277
  (s) => {
9209
9278
  loadedAt.current = Date.now();
@@ -9220,11 +9289,15 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
9220
9289
  const refresh = (0, import_react44.useCallback)(() => {
9221
9290
  if (inFlight.current) return;
9222
9291
  inFlight.current = true;
9292
+ const generation = ++loadGeneration.current;
9223
9293
  setRefreshing(true);
9224
9294
  port.load().then((s) => {
9295
+ if (generation !== loadGeneration.current) return;
9225
9296
  setRefreshError(null);
9226
9297
  apply(s);
9227
- }).catch((e) => setRefreshError(plainLoadError(e instanceof Error && e.message ? e.message : "The vault could not be read."))).finally(() => {
9298
+ }).catch((e) => {
9299
+ if (generation === loadGeneration.current) setRefreshError(plainLoadError(e instanceof Error && e.message ? e.message : "The vault could not be read."));
9300
+ }).finally(() => {
9228
9301
  inFlight.current = false;
9229
9302
  setRefreshing(false);
9230
9303
  });
@@ -9232,18 +9305,20 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
9232
9305
  port.lists.recents?.list().then(setRecents, () => void 0);
9233
9306
  }, [port, apply]);
9234
9307
  const load = (0, import_react44.useCallback)(() => {
9308
+ const generation = ++loadGeneration.current;
9235
9309
  setError(null);
9236
9310
  setRefreshError(null);
9237
9311
  let finished = false;
9238
9312
  port.load((partial) => {
9239
- if (finished) return;
9313
+ if (finished || generation !== loadGeneration.current) return;
9240
9314
  setSnap(partial);
9241
9315
  setItems(partial.items);
9242
9316
  setDeleted(partial.deleted);
9243
9317
  }).then((s) => {
9244
9318
  finished = true;
9245
- apply(s);
9319
+ if (generation === loadGeneration.current) apply(s);
9246
9320
  }).catch((e) => {
9321
+ if (generation !== loadGeneration.current) return;
9247
9322
  setSignedOut(e?.status === 401);
9248
9323
  setError(e instanceof Error ? e.message : "The vault could not be loaded.");
9249
9324
  });
@@ -9862,7 +9937,7 @@ function createAuthenticatorPort(ctx) {
9862
9937
  return {
9863
9938
  async list() {
9864
9939
  const r = await apps.listAuthenticators(api);
9865
- return (r.entries ?? []).map(entryOf);
9940
+ return { entries: (r.entries ?? []).map(entryOf), unavailableScopes: (r.unavailable_scopes ?? []).map((s) => ({ type: s.type, organizationId: s.organization_id ?? null })) };
9866
9941
  },
9867
9942
  async get(item) {
9868
9943
  try {
@@ -10076,6 +10151,7 @@ function trashItem(r, ctx) {
10076
10151
  fields: [],
10077
10152
  custom: [],
10078
10153
  authenticator: null,
10154
+ authenticatorState: "known",
10079
10155
  capabilities: { canUse: false, canEdit: false, canReveal: false, canManage: true },
10080
10156
  attachments: [],
10081
10157
  uriMatchMode: "host",
@@ -10432,7 +10508,8 @@ function fieldOf(w, def) {
10432
10508
  active: w.is_active ?? true
10433
10509
  };
10434
10510
  }
10435
- function itemOf(w, owner, defs, auth) {
10511
+ var scopeUnavailable = (owner, scopes) => scopes.some((s) => s.type === (owner.kind === "me" ? "user" : owner.kind === "organization" ? "organization" : "shared") && (s.type !== "organization" || !s.organization_id || s.organization_id === owner.organizationId));
10512
+ function itemOf(w, owner, defs, auth, state = "known", unavailable = [], inventoryOwner = owner) {
10436
10513
  const def = defs.get(w.definition_key ?? "");
10437
10514
  const a = auth.get(w.id);
10438
10515
  const cap = w.capabilities ?? {};
@@ -10450,6 +10527,7 @@ function itemOf(w, owner, defs, auth) {
10450
10527
  fields: (w.fields ?? []).filter((f) => f.execution_purpose !== "passkey_private").map((f) => fieldOf(f, def)),
10451
10528
  custom: (w.non_secret_fields ?? []).map((c) => ({ key: c["key"] ?? "", label: c["label"] ?? humanize(c["key"] ?? ""), value: c["value"] ?? "" })),
10452
10529
  authenticator: a ? { digits: a.digits, period: a.period, enabled: a.enabled } : null,
10530
+ authenticatorState: a ? "known" : state === "pending" ? "pending" : state === "unavailable" || scopeUnavailable(inventoryOwner, unavailable) || (w.fields ?? []).some((f) => f.field_key === OTP_SEED_KEY && f.is_active !== false) ? "unavailable" : "known",
10453
10531
  capabilities: { canUse: cap.can_use ?? false, canEdit: cap.can_edit ?? false, canReveal: cap.can_reveal ?? false, canManage: cap.can_manage ?? false },
10454
10532
  attachments: (w.attachments ?? []).map((a2) => ({ id: a2.id, label: a2.label, description: a2.description ?? "", fileName: a2.file_name, mediaType: a2.media_type ?? "application/octet-stream", sizeBytes: a2.size_bytes, handling: handlingOf(a2.handling), createdAt: a2.created_at, updatedAt: a2.updated_at })),
10455
10533
  uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
@@ -10486,20 +10564,19 @@ function createApiVaultPort(hostApi, options = {}) {
10486
10564
  };
10487
10565
  let defs = /* @__PURE__ */ new Map();
10488
10566
  let auth = /* @__PURE__ */ new Map();
10567
+ let authState = "pending";
10568
+ let authUnavailable = [];
10569
+ let inventoryOwners = /* @__PURE__ */ new Map();
10489
10570
  let orgs = [];
10571
+ let loadGeneration = 0;
10572
+ let authMutation = 0;
10490
10573
  const orgOf = (id, userId, mine) => {
10491
10574
  if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
10492
10575
  return mine || userId ? { kind: "me", label: "Personal", organizationId: null } : { kind: "shared", label: "Shared with me", organizationId: null };
10493
10576
  };
10494
- const ownerInOrgList = (w, via, meId) => {
10495
- if (w.organization_id) return orgOf(w.organization_id, null, false);
10496
- if (w.user_id && meId && w.user_id === meId) return { kind: "me", label: "Personal", organizationId: null };
10497
- if (via) return { kind: "organization", label: via.name, organizationId: via.id, memberShared: { userId: w.user_id ?? null } };
10498
- return { kind: "shared", label: "Shared with me", organizationId: null };
10499
- };
10500
10577
  async function refetch(id, owner) {
10501
10578
  const w = await account9.getItem(api, { path: { item_id: id } });
10502
- return itemOf(w, owner, defs, auth);
10579
+ return itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwners.get(id) ?? owner);
10503
10580
  }
10504
10581
  const visibleCache = /* @__PURE__ */ new Map();
10505
10582
  const ctx = {
@@ -10509,6 +10586,7 @@ function createApiVaultPort(hostApi, options = {}) {
10509
10586
  definition: (key) => defs.get(key),
10510
10587
  organizations: () => orgs,
10511
10588
  setAuthenticator: (itemId, entry) => {
10589
+ authMutation++;
10512
10590
  const next = new Map(auth);
10513
10591
  if (entry) next.set(itemId, entry);
10514
10592
  else next.delete(itemId);
@@ -10526,124 +10604,155 @@ function createApiVaultPort(hostApi, options = {}) {
10526
10604
  fields: createFieldsPort(ctx),
10527
10605
  lists: createListsPort(ctx, options.userState),
10528
10606
  async load(onProgress) {
10529
- const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
10530
- const authP = retrying(() => apps2.listAuthenticators(api));
10531
- const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
10532
- const sharedP = retrying(() => account9.sharedWithMe(api));
10533
- const quiet = (p) => void p.catch(() => void 0);
10534
- [catalogP, authP, userP, sharedP].forEach(quiet);
10535
- const orgItemsP = retrying(() => account9.organizationItems(api));
10536
- quiet(orgItemsP);
10537
- const raw = {
10538
- orgLists: [],
10539
- orgsKnown: options.organizations !== void 0,
10540
- meId: null
10541
- };
10542
- const unavailable = [];
10543
- let done = false;
10544
- const build = () => {
10545
- const catalog2 = raw.catalog ?? [];
10546
- defs = new Map(parseDefinitions(catalog2.filter((e) => e.is_active).map((e) => ({ key: e.key, payload: e.payload, sort_order: e.sort_order }))).map((d) => [d.key, d]));
10547
- const mineItems = raw.mine?.items ?? [];
10548
- const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
10549
- const seen = /* @__PURE__ */ new Map();
10550
- const deleted = /* @__PURE__ */ new Map();
10551
- const take = (w, owner) => {
10552
- if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
10553
- const item = itemOf(w, owner, defs, auth);
10554
- (isDeleted(w) ? deleted : seen).set(w.id, item);
10607
+ const run = async (restarts) => {
10608
+ const generation = ++loadGeneration;
10609
+ const mutationAtStart = authMutation;
10610
+ let localAuth = /* @__PURE__ */ new Map();
10611
+ let localState = "pending";
10612
+ let localUnavailable = [];
10613
+ let localDefs = /* @__PURE__ */ new Map();
10614
+ let localOrgs = [];
10615
+ const localOwners = /* @__PURE__ */ new Map();
10616
+ const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
10617
+ const authP = retrying(() => apps2.listAuthenticators(api));
10618
+ const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
10619
+ const sharedP = retrying(() => account9.sharedWithMe(api));
10620
+ const quiet = (p) => void p.catch(() => void 0);
10621
+ [catalogP, authP, userP, sharedP].forEach(quiet);
10622
+ const orgItemsP = retrying(() => account9.organizationItems(api));
10623
+ quiet(orgItemsP);
10624
+ const raw = {
10625
+ orgLists: [],
10626
+ orgsKnown: options.organizations !== void 0,
10627
+ meId: null
10555
10628
  };
10556
- for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
10557
- raw.orgLists.forEach((l, i) => {
10558
- const via = orgs[i];
10559
- for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
10560
- });
10561
- for (const w of raw.shared?.items ?? []) take(w, w.organization_id ? orgOf(w.organization_id, null, false) : { kind: "shared", label: "Shared with me", organizationId: null });
10562
- const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
10563
- return {
10564
- unavailable: [...unavailable],
10565
- ...pending.length > 0 ? { pending } : {},
10566
- items: [...seen.values()],
10567
- deleted: [...deleted.values()],
10568
- organizations: orgs,
10569
- definitions: [...defs.values()].sort((a, b) => a.sortOrder - b.sortOrder || a.label.localeCompare(b.label))
10629
+ const unavailable = [];
10630
+ let done = false;
10631
+ const build = () => {
10632
+ const catalog2 = raw.catalog ?? [];
10633
+ localDefs = new Map(parseDefinitions(catalog2.filter((e) => e.is_active).map((e) => ({ key: e.key, payload: e.payload, sort_order: e.sort_order }))).map((d) => [d.key, d]));
10634
+ const mineItems = raw.mine?.items ?? [];
10635
+ const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
10636
+ const seen = /* @__PURE__ */ new Map();
10637
+ const deleted = /* @__PURE__ */ new Map();
10638
+ const localOrgOf = (id, mine2) => id ? { kind: "organization", label: localOrgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id } : mine2 ? { kind: "me", label: "Personal", organizationId: null } : { kind: "shared", label: "Shared with me", organizationId: null };
10639
+ const take = (w, owner, inventoryOwner = owner) => {
10640
+ if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
10641
+ localOwners.set(w.id, inventoryOwner);
10642
+ const item = itemOf(w, owner, localDefs, localAuth, localState, localUnavailable, inventoryOwner);
10643
+ (isDeleted(w) ? deleted : seen).set(w.id, item);
10644
+ };
10645
+ for (const w of mineItems) take(w, localOrgOf(w.organization_id, true));
10646
+ raw.orgLists.forEach((l, i) => {
10647
+ const via = localOrgs[i];
10648
+ for (const w of l?.items ?? []) take(w, w.organization_id ? localOrgOf(w.organization_id, false) : w.user_id && meId && w.user_id === meId ? localOrgOf(null, true) : via ? { kind: "organization", label: via.name, organizationId: via.id, memberShared: { userId: w.user_id ?? null } } : localOrgOf(null, false));
10649
+ });
10650
+ for (const w of raw.shared?.items ?? []) take(w, w.organization_id ? localOrgOf(w.organization_id, false) : { kind: "shared", label: "Shared with me", organizationId: null }, { kind: "shared", label: "Shared with me", organizationId: null });
10651
+ const pending = done ? [] : [...raw.orgsKnown ? localOrgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
10652
+ return {
10653
+ unavailable: [...unavailable],
10654
+ ...pending.length > 0 ? { pending } : {},
10655
+ items: [...seen.values()],
10656
+ deleted: [...deleted.values()],
10657
+ organizations: localOrgs,
10658
+ definitions: [...localDefs.values()].sort((a, b) => a.sortOrder - b.sortOrder || a.label.localeCompare(b.label))
10659
+ };
10570
10660
  };
10571
- };
10572
- const progress = () => {
10573
- if (!done && onProgress && raw.catalog && raw.mine) onProgress(build());
10574
- };
10575
- const orgReportP = options.organizations ? null : retrying(() => platform.listMyOrganizations(api));
10576
- if (orgReportP) quiet(orgReportP);
10577
- const orgListsReady = (async () => {
10578
- const report = orgReportP ? await orgReportP : null;
10579
- raw.meId = report?.user_id ?? null;
10580
- orgs = [...new Map((options.organizations ?? (report?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
10581
- raw.orgLists = orgs.map(() => void 0);
10582
- raw.orgsKnown = true;
10583
- progress();
10584
- const one = await orgItemsP.then(
10585
- (r) => r,
10586
- (e) => {
10587
- if (e?.status === 404) {
10588
- hostProblem("GET /vault/organization-items answered 404; reading each organization vault separately", e);
10589
- return null;
10661
+ const progress = () => {
10662
+ if (!done && generation === loadGeneration && mutationAtStart === authMutation && onProgress && raw.catalog && raw.mine) onProgress(build());
10663
+ };
10664
+ const orgReportP = options.organizations ? null : retrying(() => platform.listMyOrganizations(api));
10665
+ if (orgReportP) quiet(orgReportP);
10666
+ const orgListsReady = (async () => {
10667
+ const report = orgReportP ? await orgReportP : null;
10668
+ raw.meId = report?.user_id ?? null;
10669
+ localOrgs = [...new Map((options.organizations ?? (report?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
10670
+ raw.orgLists = localOrgs.map(() => void 0);
10671
+ raw.orgsKnown = true;
10672
+ progress();
10673
+ const one = await orgItemsP.then(
10674
+ (r) => r,
10675
+ (e) => {
10676
+ if (e?.status === 404) {
10677
+ hostProblem("GET /vault/organization-items answered 404; reading each organization vault separately", e);
10678
+ return null;
10679
+ }
10680
+ return "failed";
10590
10681
  }
10591
- return "failed";
10682
+ );
10683
+ if (one) {
10684
+ const byOrg = one === "failed" ? /* @__PURE__ */ new Map() : new Map(one.views.map((v) => [v.organization_id, v.items]));
10685
+ const failed = one === "failed" ? new Set(localOrgs.map((o) => o.id)) : new Set(one.unavailable);
10686
+ const settled = localOrgs.map((o, i) => {
10687
+ const items = byOrg.get(o.id);
10688
+ if (failed.has(o.id) || items === void 0) return Promise.reject(new Error(`${o.name} is unavailable`));
10689
+ raw.orgLists[i] = { items, count: items.length };
10690
+ return Promise.resolve(raw.orgLists[i]);
10691
+ });
10692
+ settled.forEach(quiet);
10693
+ progress();
10694
+ return settled;
10592
10695
  }
10593
- );
10594
- if (one) {
10595
- const byOrg = one === "failed" ? /* @__PURE__ */ new Map() : new Map(one.views.map((v) => [v.organization_id, v.items]));
10596
- const failed = one === "failed" ? new Set(orgs.map((o) => o.id)) : new Set(one.unavailable);
10597
- const settled = orgs.map((o, i) => {
10598
- const items = byOrg.get(o.id);
10599
- if (failed.has(o.id) || items === void 0) return Promise.reject(new Error(`${o.name} is unavailable`));
10600
- raw.orgLists[i] = { items, count: items.length };
10601
- return Promise.resolve(raw.orgLists[i]);
10696
+ return localOrgs.map((o, i) => {
10697
+ const p = retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id }));
10698
+ const arrived = p.then((l) => {
10699
+ raw.orgLists[i] = l;
10700
+ progress();
10701
+ return l;
10702
+ });
10703
+ quiet(arrived);
10704
+ return arrived;
10602
10705
  });
10603
- settled.forEach(quiet);
10706
+ })();
10707
+ quiet(orgListsReady);
10708
+ const authDone = authP.then((a) => {
10709
+ localUnavailable = a.unavailable_scopes ?? [];
10710
+ const fresh = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
10711
+ localAuth = fresh;
10712
+ localState = "known";
10713
+ if (localUnavailable.length) unavailable.push("One-time codes");
10604
10714
  progress();
10605
- return settled;
10606
- }
10607
- return orgs.map((o, i) => {
10608
- const p = retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id }));
10609
- const arrived = p.then((l) => {
10610
- raw.orgLists[i] = l;
10611
- progress();
10612
- return l;
10613
- });
10614
- quiet(arrived);
10615
- return arrived;
10715
+ }, () => {
10716
+ localState = "unavailable";
10717
+ unavailable.push("One-time codes");
10616
10718
  });
10617
- })();
10618
- quiet(orgListsReady);
10619
- const authDone = authP.then((a) => {
10620
- auth = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
10621
- progress();
10622
- }, () => {
10623
- unavailable.push("One-time codes");
10624
- });
10625
- const sharedDone = sharedP.then((sh) => {
10626
- raw.shared = sh;
10719
+ const sharedDone = sharedP.then((sh) => {
10720
+ raw.shared = sh;
10721
+ progress();
10722
+ }, () => {
10723
+ raw.shared = { items: [], count: 0 };
10724
+ unavailable.push("Shared with me");
10725
+ });
10726
+ const [catalog, mine] = await Promise.all([catalogP, userP]);
10727
+ raw.catalog = catalog;
10728
+ raw.mine = mine;
10627
10729
  progress();
10628
- }, () => {
10629
- raw.shared = { items: [], count: 0 };
10630
- unavailable.push("Shared with me");
10631
- });
10632
- const [catalog, mine] = await Promise.all([catalogP, userP]);
10633
- raw.catalog = catalog;
10634
- raw.mine = mine;
10635
- progress();
10636
- const orgPs = await orgListsReady;
10637
- const orgSettled = await Promise.allSettled(orgPs);
10638
- orgSettled.forEach((r, i) => {
10639
- if (r.status === "rejected") {
10640
- raw.orgLists[i] = { items: [], count: 0 };
10641
- unavailable.push(orgs[i]?.name ?? "An organization");
10730
+ const orgPs = await orgListsReady;
10731
+ const orgSettled = await Promise.allSettled(orgPs);
10732
+ orgSettled.forEach((r, i) => {
10733
+ if (r.status === "rejected") {
10734
+ raw.orgLists[i] = { items: [], count: 0 };
10735
+ unavailable.push(localOrgs[i]?.name ?? "An organization");
10736
+ }
10737
+ });
10738
+ await Promise.all([authDone, sharedDone]);
10739
+ done = true;
10740
+ if (generation === loadGeneration && mutationAtStart !== authMutation) {
10741
+ if (restarts >= 2) throw new Error("Authenticator changed while loading. Retry");
10742
+ return run(restarts + 1);
10642
10743
  }
10643
- });
10644
- await Promise.all([authDone, sharedDone]);
10645
- done = true;
10646
- return build();
10744
+ const snapshot = build();
10745
+ if (generation === loadGeneration) {
10746
+ defs = localDefs;
10747
+ auth = localAuth;
10748
+ authState = localState;
10749
+ authUnavailable = localUnavailable;
10750
+ inventoryOwners = localOwners;
10751
+ orgs = localOrgs;
10752
+ }
10753
+ return snapshot;
10754
+ };
10755
+ return run(0);
10647
10756
  },
10648
10757
  async reveal(item, fieldKey2) {
10649
10758
  const field = item.fields.find((f) => f.key === fieldKey2);