@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/CHANGELOG.md +10 -1
- package/dist/index.cjs +274 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +324 -215
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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(() =>
|
|
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
|
|
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 :
|
|
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(() =>
|
|
2744
|
-
|
|
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.
|
|
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
|
|
2866
|
-
|
|
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) =>
|
|
2892
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
(
|
|
6649
|
-
|
|
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
|
-
|
|
6660
|
-
const [
|
|
6661
|
-
(
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
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.
|
|
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 }) :
|
|
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) =>
|
|
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
|
-
|
|
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
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
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
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
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
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
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
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
raw.
|
|
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
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
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
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
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);
|