@ai-matrx/vault 0.1.11 → 0.1.13
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 +21 -3
- package/dist/index.cjs +222 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -4
- package/dist/index.d.ts +62 -4
- package/dist/index.js +285 -114
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -136,9 +136,11 @@ var init_keepass_xml_worker_client = __esm({
|
|
|
136
136
|
var src_exports = {};
|
|
137
137
|
__export(src_exports, {
|
|
138
138
|
CATEGORIES: () => CATEGORIES,
|
|
139
|
+
CONFIRM_RETURN_KEY: () => CONFIRM_RETURN_KEY,
|
|
139
140
|
DEFAULT_LOCATION: () => DEFAULT_LOCATION,
|
|
140
141
|
GenerateButton: () => GenerateButton,
|
|
141
142
|
HIDDEN_ITEM_TAG: () => HIDDEN_ITEM_TAG,
|
|
143
|
+
IdentityGate: () => IdentityGate,
|
|
142
144
|
LOCKED_MESSAGE: () => LOCKED_MESSAGE,
|
|
143
145
|
VaultApp: () => VaultApp,
|
|
144
146
|
VaultLockedError: () => VaultLockedError,
|
|
@@ -156,7 +158,10 @@ __export(src_exports, {
|
|
|
156
158
|
matchesQuery: () => matchesQuery,
|
|
157
159
|
needsRecentSignIn: () => needsRecentSignIn,
|
|
158
160
|
parseDefinitions: () => parseDefinitions,
|
|
159
|
-
|
|
161
|
+
siteDomainOf: () => siteDomainOf,
|
|
162
|
+
sortItems: () => sortItems,
|
|
163
|
+
useConfirmed: () => useConfirmed,
|
|
164
|
+
wasCancelled: () => wasCancelled
|
|
160
165
|
});
|
|
161
166
|
module.exports = __toCommonJS(src_exports);
|
|
162
167
|
|
|
@@ -384,9 +389,20 @@ var FingerprintGlyph = glyph(/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(impor
|
|
|
384
389
|
var SendGlyph = glyph(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14.5 21.7a.5.5 0 0 0 .9 0L22 3a.5.5 0 0 0-.6-.6L2.3 9.1a.5.5 0 0 0 0 .9l7.9 3.2a2 2 0 0 1 1.1 1.1zM21.9 2.1 10.9 13.1" }), [1, 1]);
|
|
385
390
|
|
|
386
391
|
// src/auth/identity.ts
|
|
392
|
+
var CONFIRM_RETURN_KEY = "matrx-vault:confirming-as";
|
|
393
|
+
var RETURN_WINDOW_MS = 15 * 6e4;
|
|
387
394
|
var SAME_PERSON = "That signed in a different account. Use the account this vault belongs to.";
|
|
388
395
|
function createSupabaseIdentity(auth, options = {}) {
|
|
389
396
|
let me = null;
|
|
397
|
+
const now = options.now ?? Date.now;
|
|
398
|
+
const store = () => {
|
|
399
|
+
if (options.store) return options.store;
|
|
400
|
+
try {
|
|
401
|
+
return globalThis.sessionStorage ?? null;
|
|
402
|
+
} catch {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
};
|
|
390
406
|
const who = async () => {
|
|
391
407
|
const { data } = await auth.getUser();
|
|
392
408
|
if (!data.user) throw new Error("You are signed out. Sign in again.");
|
|
@@ -403,10 +419,35 @@ function createSupabaseIdentity(auth, options = {}) {
|
|
|
403
419
|
return { email: u.email ?? null, providers: [...names].filter((p) => p !== "email" && p !== "phone"), hasPassword: names.has("email") };
|
|
404
420
|
},
|
|
405
421
|
async withProvider(provider) {
|
|
406
|
-
await who();
|
|
422
|
+
const u = await who();
|
|
423
|
+
store()?.setItem(CONFIRM_RETURN_KEY, JSON.stringify({ id: u.id, email: u.email ?? null, at: now() }));
|
|
407
424
|
const redirectTo = options.redirectTo?.() ?? globalThis.location?.href;
|
|
408
425
|
const { error } = await auth.signInWithOAuth({ provider, ...redirectTo ? { options: { redirectTo } } : {} });
|
|
409
|
-
if (error)
|
|
426
|
+
if (error) {
|
|
427
|
+
store()?.removeItem(CONFIRM_RETURN_KEY);
|
|
428
|
+
throw new Error(error.message);
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
async checkReturn() {
|
|
432
|
+
const s = store();
|
|
433
|
+
const raw = s?.getItem(CONFIRM_RETURN_KEY) ?? null;
|
|
434
|
+
if (!s || raw === null) return null;
|
|
435
|
+
s.removeItem(CONFIRM_RETURN_KEY);
|
|
436
|
+
let expected;
|
|
437
|
+
try {
|
|
438
|
+
expected = JSON.parse(raw);
|
|
439
|
+
} catch {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
if (typeof expected.id !== "string" || typeof expected.at !== "number" || now() - expected.at > RETURN_WINDOW_MS) return null;
|
|
443
|
+
const { data } = await auth.getUser();
|
|
444
|
+
if (!data.user || data.user.id === expected.id) return null;
|
|
445
|
+
const email = typeof expected.email === "string" && expected.email ? expected.email : null;
|
|
446
|
+
const message2 = `That signed in a different account, so it was signed out here.${email ? ` Sign in again as ${email}.` : " Sign in again."}`;
|
|
447
|
+
me = null;
|
|
448
|
+
if (options.onDifferentPerson) await options.onDifferentPerson(message2);
|
|
449
|
+
else await auth.signOut?.({ scope: "local" });
|
|
450
|
+
return message2;
|
|
410
451
|
},
|
|
411
452
|
async withPassword(password) {
|
|
412
453
|
const u = await who();
|
|
@@ -452,6 +493,18 @@ var providerLabel = (p) => PROVIDER_LABEL[p] ?? p.charAt(0).toUpperCase() + p.sl
|
|
|
452
493
|
function IdentityGate({ identity, children }) {
|
|
453
494
|
const [asking, setAsking] = (0, import_react2.useState)(false);
|
|
454
495
|
const waiters = (0, import_react2.useRef)([]);
|
|
496
|
+
const [returnProblem, setReturnProblem] = (0, import_react2.useState)(null);
|
|
497
|
+
(0, import_react2.useEffect)(() => {
|
|
498
|
+
if (!identity?.checkReturn) return;
|
|
499
|
+
let live = true;
|
|
500
|
+
identity.checkReturn().then(
|
|
501
|
+
(problem) => live && problem && setReturnProblem(problem),
|
|
502
|
+
(e) => live && setReturnProblem(e instanceof Error ? e.message : "The account that came back could not be checked.")
|
|
503
|
+
);
|
|
504
|
+
return () => {
|
|
505
|
+
live = false;
|
|
506
|
+
};
|
|
507
|
+
}, [identity]);
|
|
455
508
|
const confirmed = async (run) => {
|
|
456
509
|
try {
|
|
457
510
|
return await run();
|
|
@@ -472,7 +525,14 @@ function IdentityGate({ identity, children }) {
|
|
|
472
525
|
};
|
|
473
526
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Ctx2.Provider, { value: confirmed, children: [
|
|
474
527
|
children,
|
|
475
|
-
identity ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ConfirmIdentityDialog, { open: asking, identity, onDone: () => settle(true), onCancel: () => settle(false) }) : null
|
|
528
|
+
identity ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ConfirmIdentityDialog, { open: asking, identity, onDone: () => settle(true), onCancel: () => settle(false) }) : null,
|
|
529
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Dialog, { open: returnProblem !== null, onOpenChange: (o) => o ? void 0 : setReturnProblem(null), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.DialogContent, { size: "sm", children: [
|
|
530
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.DialogHeader, { children: [
|
|
531
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.DialogTitle, { children: "Different account" }),
|
|
532
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.DialogDescription, { children: returnProblem })
|
|
533
|
+
] }),
|
|
534
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls.Button, { variant: "primary", onClick: () => setReturnProblem(null), children: "OK" }) })
|
|
535
|
+
] }) })
|
|
476
536
|
] });
|
|
477
537
|
}
|
|
478
538
|
var wasCancelled = (e) => e instanceof Error && e.message === CANCELLED;
|
|
@@ -536,7 +596,7 @@ function ConfirmIdentityDialog({ open, identity, onDone, onCancel }) {
|
|
|
536
596
|
e.preventDefault();
|
|
537
597
|
if (password) void attempt(() => identity.withPassword(password));
|
|
538
598
|
}, children: [
|
|
539
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls.Field, { className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "Your password", "aria-label": "Your password", value: password, onChange: (e) => setPassword(e.target.value) }),
|
|
599
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls.Field, { className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "Your password", "aria-label": "Your password", value: password, onChange: (e) => setPassword(e.target.value), autoFocus: true }),
|
|
540
600
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls.Button, { variant: "outline", type: "submit", disabled: busy || !password, children: "Confirm" })
|
|
541
601
|
] }) : null,
|
|
542
602
|
account10?.email ? codeSent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { className: "flex gap-2", onSubmit: (e) => {
|
|
@@ -664,6 +724,12 @@ function Panel({ title, open = true, onClose, children, footer, size = "lg" }) {
|
|
|
664
724
|
footer ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.DialogFooter, { children: footer }) : null
|
|
665
725
|
] }) });
|
|
666
726
|
}
|
|
727
|
+
function PanelFooter({ status, children }) {
|
|
728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex w-full flex-wrap items-center justify-end gap-2", children: [
|
|
729
|
+
status ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-w-0 flex-1 basis-full sm:basis-0", children: status }) : null,
|
|
730
|
+
children
|
|
731
|
+
] });
|
|
732
|
+
}
|
|
667
733
|
var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
|
|
668
734
|
|
|
669
735
|
// src/FieldRows.tsx
|
|
@@ -674,7 +740,7 @@ function SecretText({ value, multiline }) {
|
|
|
674
740
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "break-all font-mono text-sm tracking-wide", children: [...value].map((ch, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: /[0-9]/.test(ch) ? "text-primary" : /[^A-Za-z0-9]/.test(ch) ? "text-warning" : void 0, children: ch }, i)) });
|
|
675
741
|
}
|
|
676
742
|
var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
677
|
-
function SecretRow({ port, item, field, extra }) {
|
|
743
|
+
function SecretRow({ port, item, field, extra, onTurnOn }) {
|
|
678
744
|
const confirmed = useConfirmed();
|
|
679
745
|
const copyValue2 = useCopy();
|
|
680
746
|
const secret = useTransientSecret();
|
|
@@ -683,7 +749,7 @@ function SecretRow({ port, item, field, extra }) {
|
|
|
683
749
|
const [error, setError] = (0, import_react5.useState)(null);
|
|
684
750
|
const sealed = field.handling === "sealed";
|
|
685
751
|
const visible = field.handling === "visible";
|
|
686
|
-
const off = field.active === false;
|
|
752
|
+
const off = field.active === false || item.turnedOff === true;
|
|
687
753
|
const canSee = !sealed && !off && (visible ? item.capabilities.canUse : item.capabilities.canReveal);
|
|
688
754
|
(0, import_react5.useEffect)(() => {
|
|
689
755
|
if (!visible || !canSee) return;
|
|
@@ -728,10 +794,27 @@ function SecretRow({ port, item, field, extra }) {
|
|
|
728
794
|
top: multiline && shown !== null,
|
|
729
795
|
actions: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
730
796
|
extra,
|
|
797
|
+
off && onTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TurnOnButton, { label: field.label, onTurnOn }) : null,
|
|
731
798
|
canSee && !visible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: secret.value !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EyeOffGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EyeGlyph, {}), "aria-label": secret.value !== null ? `Hide ${field.label}` : `Show ${field.label}`, disabled: busy, onClick: () => void toggle2() }) : null,
|
|
732
799
|
canSee ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons2.CopyIcon, {}), "aria-label": `Copy ${field.label}`, disabled: busy, onClick: () => void copy() }) : null
|
|
733
800
|
] }),
|
|
734
|
-
children: sealed ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LockGlyph, {}), children: "
|
|
801
|
+
children: sealed ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LockGlyph, {}), children: "Never shown" }) : off ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) : error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate text-destructive", title: error, children: error }) : shown !== null ? visible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: (0, import_design_system5.cn)("block", multiline ? "whitespace-pre-wrap break-words" : "truncate"), children: shown || "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SecretText, { value: shown, multiline }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: (0, import_design_system5.cn)("block truncate text-muted-foreground", !visible && "tracking-widest"), children: visible ? "\u2026" : MASK })
|
|
802
|
+
}
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
function TurnOnButton({ label, onTurnOn }) {
|
|
806
|
+
const [busy, setBusy] = (0, import_react5.useState)(false);
|
|
807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
808
|
+
import_controls2.Button,
|
|
809
|
+
{
|
|
810
|
+
variant: "outline",
|
|
811
|
+
"aria-label": `Turn on ${label}`,
|
|
812
|
+
disabled: busy,
|
|
813
|
+
onClick: () => {
|
|
814
|
+
setBusy(true);
|
|
815
|
+
void onTurnOn().finally(() => setBusy(false));
|
|
816
|
+
},
|
|
817
|
+
children: "Turn on"
|
|
735
818
|
}
|
|
736
819
|
);
|
|
737
820
|
}
|
|
@@ -870,14 +953,27 @@ function loginSiteOf(item) {
|
|
|
870
953
|
return raw.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? "";
|
|
871
954
|
}
|
|
872
955
|
}
|
|
956
|
+
var TWO_PART_SUFFIX = /* @__PURE__ */ new Set(["co", "com", "org", "net", "gov", "edu", "ac", "ne", "or"]);
|
|
957
|
+
function siteDomainOf(host) {
|
|
958
|
+
const h = host.toLowerCase().replace(/\.$/, "");
|
|
959
|
+
if (!h || /^[\d.]+$/.test(h) || h.includes(":")) return h;
|
|
960
|
+
const labels = h.split(".").filter(Boolean);
|
|
961
|
+
if (labels.length <= 2) return labels.join(".");
|
|
962
|
+
const sld = labels[labels.length - 2] ?? "";
|
|
963
|
+
const tld = labels[labels.length - 1] ?? "";
|
|
964
|
+
const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
|
|
965
|
+
return labels.slice(-keep).join(".");
|
|
966
|
+
}
|
|
873
967
|
function sortItems(items, sort) {
|
|
874
968
|
const out = [...items];
|
|
875
969
|
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
876
970
|
if (sort === "name") return out.sort(byName);
|
|
877
|
-
if (sort === "website")
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
971
|
+
if (sort === "website")
|
|
972
|
+
return out.sort((a, b) => {
|
|
973
|
+
const x = loginSiteOf(a), y = loginSiteOf(b);
|
|
974
|
+
if (!x || !y) return x ? -1 : y ? 1 : byName(a, b);
|
|
975
|
+
return siteDomainOf(x).localeCompare(siteDomainOf(y)) || x.localeCompare(y) || byName(a, b);
|
|
976
|
+
});
|
|
881
977
|
if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
882
978
|
return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
883
979
|
}
|
|
@@ -1297,7 +1393,10 @@ function ActivityPanel({ item, port, onClose }) {
|
|
|
1297
1393
|
{
|
|
1298
1394
|
title: "Activity",
|
|
1299
1395
|
onClose,
|
|
1300
|
-
footer:
|
|
1396
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1397
|
+
hasMore ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_controls3.Button, { variant: "outline", disabled: loading, onClick: () => setLimit((n) => Math.min(MAX, n * 2)), children: loading ? "Loading\u2026" : "Show more" }) : null,
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_controls3.Button, { variant: "primary", onClick: onClose, children: "Done" })
|
|
1399
|
+
] }),
|
|
1301
1400
|
children: [
|
|
1302
1401
|
error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
|
|
1303
1402
|
entries === null ? loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Empty, { children: "Reading activity\u2026" }) : null : entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Empty, { children: "Nothing has happened yet." }) : groupByDay(entries, now).map((day) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VaultSection, { title: day.label, children: collapseRuns(
|
|
@@ -1380,7 +1479,10 @@ function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
|
1380
1479
|
{
|
|
1381
1480
|
title: "Password history",
|
|
1382
1481
|
onClose,
|
|
1383
|
-
footer:
|
|
1482
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1483
|
+
page?.nextBefore ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_controls4.Button, { variant: "outline", disabled: more, onClick: () => void loadMore(), children: more ? "Loading\u2026" : "Show earlier" }) : null,
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_controls4.Button, { variant: "primary", onClick: onClose, children: "Done" })
|
|
1485
|
+
] }),
|
|
1384
1486
|
children: !eligible ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Empty, { children: "History is kept only for your own items." }) : loading && !page ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Empty, { children: "Reading history\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1385
1487
|
error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
|
|
1386
1488
|
notice ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "status", className: "px-1 text-sm text-success", children: notice }) : null,
|
|
@@ -1985,6 +2087,7 @@ var import_confirm_opener2 = require("@ai-matrx/kit/confirm-opener");
|
|
|
1985
2087
|
|
|
1986
2088
|
// src/authenticator/port.ts
|
|
1987
2089
|
var MFA_METHOD_KEY = "mfa_method";
|
|
2090
|
+
var OTP_SEED_KEY = "totp_seed";
|
|
1988
2091
|
function mfaMethodOf(item) {
|
|
1989
2092
|
const v = item.custom.find((c) => c.key === MFA_METHOD_KEY)?.value;
|
|
1990
2093
|
return v === "sms" ? "sms" : v ? "push_or_other" : null;
|
|
@@ -2343,7 +2446,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2343
2446
|
const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
|
|
2344
2447
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
2345
2448
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { "aria-label": "One-time passwords", className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
2346
|
-
header,
|
|
2449
|
+
header ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
|
|
2347
2450
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
|
|
2348
2451
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-w-0 items-baseline gap-2", children: [
|
|
2349
2452
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "truncate text-sm font-semibold text-foreground", children: "One-time passwords" }),
|
|
@@ -2355,7 +2458,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2355
2458
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShieldGlyph, { className: "size-6" }) }),
|
|
2356
2459
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-medium text-foreground", children: "No one-time passwords yet" }),
|
|
2357
2460
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_controls9.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add one-time password" })
|
|
2358
|
-
] }) : groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(VaultSection, {
|
|
2461
|
+
] }) : groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(VaultSection, { title: g.label, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2359
2462
|
OtpListRow,
|
|
2360
2463
|
{
|
|
2361
2464
|
port,
|
|
@@ -2492,9 +2595,9 @@ function sandboxBlocker(envKeyDraft, savedEnvKey) {
|
|
|
2492
2595
|
return null;
|
|
2493
2596
|
}
|
|
2494
2597
|
var HANDLING_WORDS = {
|
|
2495
|
-
visible: { label: "
|
|
2496
|
-
revealable: { label: "
|
|
2497
|
-
sealed: { label: "
|
|
2598
|
+
visible: { label: "Always shown", hint: "Anyone who can use it can show or copy it" },
|
|
2599
|
+
revealable: { label: "Hidden", hint: "Showing or copying it needs reveal access" },
|
|
2600
|
+
sealed: { label: "Never shown", hint: "No one can see it. Automation can still use it." }
|
|
2498
2601
|
};
|
|
2499
2602
|
function handlingChoices(current) {
|
|
2500
2603
|
return current === "sealed" ? ["sealed"] : ["visible", "revealable", "sealed"];
|
|
@@ -2676,7 +2779,7 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2676
2779
|
}
|
|
2677
2780
|
) }),
|
|
2678
2781
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VaultRow, { label: "Editable", hint: quietHint(field.editable ? "The value can be changed" : "The value is locked"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls10.Switch, { "aria-label": "Editable", checked: field.editable, disabled: locked, onCheckedChange: (v) => void update("editable", { editable: v }) }) }),
|
|
2679
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VaultRow, { label: "
|
|
2782
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VaultRow, { label: "Turned on", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls10.Switch, { "aria-label": "Turned on", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: v }) }) })
|
|
2680
2783
|
] }),
|
|
2681
2784
|
error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Problem, { children: error }) : null
|
|
2682
2785
|
] });
|
|
@@ -2744,7 +2847,7 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2744
2847
|
f.envKey
|
|
2745
2848
|
] }) : null,
|
|
2746
2849
|
f.injectIntoSandbox ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
|
|
2747
|
-
!f.active ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-
|
|
2850
|
+
!f.active ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
|
|
2748
2851
|
] })
|
|
2749
2852
|
},
|
|
2750
2853
|
f.id
|
|
@@ -4686,7 +4789,7 @@ var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
|
4686
4789
|
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
4687
4790
|
const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
|
|
4688
4791
|
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
4689
|
-
const initial = site
|
|
4792
|
+
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
4690
4793
|
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
4691
4794
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: (0, import_design_system12.cn)("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
4692
4795
|
}
|
|
@@ -4715,7 +4818,7 @@ var TOO_BIG = "Files over 25 MB can't be stored.";
|
|
|
4715
4818
|
var PROTECTION = [
|
|
4716
4819
|
{ value: "visible", label: "Open", title: "Anyone who can use the item can download it" },
|
|
4717
4820
|
{ value: "revealable", label: "Protected", title: "Downloading needs a recent sign-in" },
|
|
4718
|
-
{ value: "sealed", label: "
|
|
4821
|
+
{ value: "sealed", label: "Never shown", title: "Only automation can use it, never a person" }
|
|
4719
4822
|
];
|
|
4720
4823
|
function FilesSection({ item, port, editing, onChanged }) {
|
|
4721
4824
|
const confirmed = useConfirmed();
|
|
@@ -4782,7 +4885,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4782
4885
|
{
|
|
4783
4886
|
label: a.label,
|
|
4784
4887
|
hint: a.description || void 0,
|
|
4785
|
-
actions: a.handling === "sealed" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_controls16.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LockGlyph, {}), children: "
|
|
4888
|
+
actions: a.handling === "sealed" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_controls16.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LockGlyph, {}), children: "Never shown" }) : canDownload(item, a) ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_controls16.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_icons8.DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: busy !== null, onClick: () => void download(a) }) : null,
|
|
4786
4889
|
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FileName, { file: a })
|
|
4787
4890
|
},
|
|
4788
4891
|
a.id
|
|
@@ -5004,7 +5107,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
5004
5107
|
canSee ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Button, { variant: "quiet", icon: codes ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EyeOffGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EyeGlyph, {}), "aria-label": codes ? "Hide codes" : "Show codes", disabled: busy, onClick: () => void toggle2() }) : null,
|
|
5005
5108
|
canEdit && !sealed ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PencilGlyph, {}), "aria-label": "Replace all codes", disabled: busy, onClick: () => setDraft("") }) : null
|
|
5006
5109
|
] }),
|
|
5007
|
-
children: sealed ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LockGlyph, {}), children: "
|
|
5110
|
+
children: sealed ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LockGlyph, {}), children: "Never shown" }) : codes ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("ul", { className: "flex flex-col gap-0.5", "aria-label": "Recovery codes", children: [
|
|
5008
5111
|
codes.map((code, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex min-h-7 items-center gap-1", children: [
|
|
5009
5112
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("code", { className: "min-w-0 flex-1 break-all font-mono text-sm text-foreground", children: code }),
|
|
5010
5113
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_icons9.CopyIcon, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue2(code, "Recovery code") }),
|
|
@@ -5327,10 +5430,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5327
5430
|
title: "Move or copy",
|
|
5328
5431
|
size: "md",
|
|
5329
5432
|
onClose,
|
|
5330
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime24.
|
|
5331
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StatusLine, { error, notice }),
|
|
5332
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_controls19.Button, { variant: "outline", className: "ml-auto", onClick: onClose, children: "Close" })
|
|
5333
|
-
] }),
|
|
5433
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_controls19.Button, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5334
5434
|
children: nothing ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(VaultSection, { children: [
|
|
5335
5435
|
canMove && moves.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
5336
5436
|
VaultRow,
|
|
@@ -5445,10 +5545,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5445
5545
|
title: "Share",
|
|
5446
5546
|
size: "md",
|
|
5447
5547
|
onClose,
|
|
5448
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime25.
|
|
5449
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusLine, { error, notice }),
|
|
5450
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "primary", className: "ml-auto", onClick: onClose, children: "Done" })
|
|
5451
|
-
] }),
|
|
5548
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5452
5549
|
children: [
|
|
5453
5550
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(VaultSection, { title: "Who has access", children: [
|
|
5454
5551
|
isOrg ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AccessLine, { glyph: BuildingGlyph, who: `${orgName} admins`, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AccessLine, { glyph: PersonGlyph, who: "You", meta: "Owner", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }),
|
|
@@ -5734,6 +5831,27 @@ function ItemPane(props) {
|
|
|
5734
5831
|
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "The value could not be read.");
|
|
5735
5832
|
}
|
|
5736
5833
|
}
|
|
5834
|
+
const offFields = item ? item.fields.filter((f) => !f.active) : [];
|
|
5835
|
+
const itemOff = item?.turnedOff === true;
|
|
5836
|
+
const seedField = item?.fields.find((f) => f.key === OTP_SEED_KEY) ?? null;
|
|
5837
|
+
const canTurnOn = Boolean(item && canEdit);
|
|
5838
|
+
async function turnOn(fields) {
|
|
5839
|
+
if (!item) return;
|
|
5840
|
+
setError(null);
|
|
5841
|
+
try {
|
|
5842
|
+
if (item.turnedOff) await confirmed(() => port.fields.updateItem(item, { active: true }));
|
|
5843
|
+
for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
|
|
5844
|
+
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
5845
|
+
const codes = await port.authenticator.get(item);
|
|
5846
|
+
if (codes && !codes.enabled) await confirmed(() => port.authenticator.setEnabled(item, true));
|
|
5847
|
+
}
|
|
5848
|
+
onChanged();
|
|
5849
|
+
} catch (e) {
|
|
5850
|
+
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
|
|
5851
|
+
onChanged();
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
5737
5855
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
5738
5856
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
5739
5857
|
const metaValue = (key) => draft.values[key] ?? item?.custom.find((c) => c.key === key)?.value ?? "";
|
|
@@ -5742,6 +5860,10 @@ function ItemPane(props) {
|
|
|
5742
5860
|
const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
|
|
5743
5861
|
const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
|
|
5744
5862
|
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BuildingGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_icons11.UsersIcon, {}) } : null;
|
|
5863
|
+
const sameNamed = (id) => {
|
|
5864
|
+
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
5865
|
+
return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
|
|
5866
|
+
};
|
|
5745
5867
|
const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
|
|
5746
5868
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5747
5869
|
const header = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-5", children: [
|
|
@@ -5825,6 +5947,10 @@ function ItemPane(props) {
|
|
|
5825
5947
|
header,
|
|
5826
5948
|
error ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
|
|
5827
5949
|
notice && !editing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
|
|
5950
|
+
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
|
|
5951
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.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` }),
|
|
5952
|
+
canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
5953
|
+
] }) : null,
|
|
5828
5954
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
5829
5955
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(VaultSection, { children: [
|
|
5830
5956
|
mode === "new" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultRow, { label: "Save to", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
@@ -5837,11 +5963,11 @@ function ItemPane(props) {
|
|
|
5837
5963
|
searchPlaceholder: "Find an organization",
|
|
5838
5964
|
groups: [
|
|
5839
5965
|
{ heading: "Just you", options: ["me"] },
|
|
5840
|
-
...organizations.length > 0 ? [{ heading: "Organizations", options: organizations.map((o) => o.id) }] : [],
|
|
5966
|
+
...organizations.length > 0 ? [{ heading: "Organizations", options: [...organizations].sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }) || a.id.localeCompare(b.id)).map((o) => o.id) }] : [],
|
|
5841
5967
|
{ heading: "Send", options: ["person"] }
|
|
5842
5968
|
],
|
|
5843
5969
|
getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
|
|
5844
|
-
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : null,
|
|
5970
|
+
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
|
|
5845
5971
|
renderIcon: (v) => v === "me" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BuildingGlyph, { className: "size-4" })
|
|
5846
5972
|
}
|
|
5847
5973
|
) }) : null,
|
|
@@ -5916,7 +6042,7 @@ function ItemPane(props) {
|
|
|
5916
6042
|
i
|
|
5917
6043
|
)),
|
|
5918
6044
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
5919
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator), item, port, onEnrolled: onChanged }),
|
|
6045
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
5920
6046
|
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
5921
6047
|
] }),
|
|
5922
6048
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
|
|
@@ -5949,7 +6075,7 @@ function ItemPane(props) {
|
|
|
5949
6075
|
) : null,
|
|
5950
6076
|
draft.secrets.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(CustomEditRow, { label: s.label, value: s.value, secret: true, onLabel: (v) => patch({ secrets: draft.secrets.map((x, j) => j === i ? { ...x, label: v } : x) }), onValue: (v) => patch({ secrets: draft.secrets.map((x, j) => j === i ? { ...x, value: v } : x) }), onRemove: () => patch({ secrets: draft.secrets.filter((_, j) => j !== i) }) }, `s${i}`)),
|
|
5951
6077
|
extraCustom.map((c) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(CustomEditRow, { label: c.label, value: c.value, secret: false, onLabel: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, label: v } : x) }), onValue: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, value: v } : x) }), onRemove: () => patch({ custom: draft.custom.filter((x) => x.key !== c.key) }) }, c.key)),
|
|
5952
|
-
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "
|
|
6078
|
+
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
|
|
5953
6079
|
]
|
|
5954
6080
|
}
|
|
5955
6081
|
),
|
|
@@ -5963,11 +6089,15 @@ function ItemPane(props) {
|
|
|
5963
6089
|
}
|
|
5964
6090
|
const field = item.fields.find((x) => x.key === f.key);
|
|
5965
6091
|
if (isRecoveryCodesField(f)) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
|
|
5966
|
-
return field ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SecretRow, { port, item, field }, field.id) : null;
|
|
6092
|
+
return field ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SecretRow, { port, item, field, onTurnOn: turnOnOne(field) }, field.id) : null;
|
|
5967
6093
|
}),
|
|
5968
|
-
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SecretRow, { port, item, field: f }, f.id)),
|
|
6094
|
+
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f) }, f.id)),
|
|
5969
6095
|
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
5970
|
-
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TotpRow, { port, item, onChanged }) :
|
|
6096
|
+
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
|
|
6097
|
+
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6098
|
+
// which would invite replacing a working two-factor secret.
|
|
6099
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultRow, { label: "One-time password", actions: canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TurnOnButton, { label: "One-time password", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
6100
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "One-time password", onAdd: canEdit ? () => onMode("edit") : null, children: "Set up" }),
|
|
5971
6101
|
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
5972
6102
|
] }),
|
|
5973
6103
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { children: item.notes ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
|
|
@@ -5999,7 +6129,7 @@ function subtitleOf(item, withOwner) {
|
|
|
5999
6129
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6000
6130
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6001
6131
|
}
|
|
6002
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header }) {
|
|
6132
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
|
|
6003
6133
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6004
6134
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
6005
6135
|
const ordered = [...pinned, ...rest];
|
|
@@ -6018,7 +6148,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6018
6148
|
listRef.current?.querySelector(`[data-item="${next.id}"]`)?.scrollIntoView({ block: "nearest" });
|
|
6019
6149
|
}
|
|
6020
6150
|
};
|
|
6021
|
-
const mixedOwners = new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6151
|
+
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6022
6152
|
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
|
|
6023
6153
|
const sortLabel = SORTS2.find((s) => s.value === sort)?.label ?? "Name";
|
|
6024
6154
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
@@ -6236,6 +6366,9 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6236
6366
|
|
|
6237
6367
|
// src/lists/TrashView.tsx
|
|
6238
6368
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
6369
|
+
function trashLineOf(item) {
|
|
6370
|
+
return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${(0, import_format9.formatAbsoluteDate)(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
|
|
6371
|
+
}
|
|
6239
6372
|
function TrashView({ port, deleted, query, header, onChanged }) {
|
|
6240
6373
|
const confirmed = useConfirmed();
|
|
6241
6374
|
const [busyId, setBusyId] = (0, import_react30.useState)(null);
|
|
@@ -6247,7 +6380,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6247
6380
|
setMessage(null);
|
|
6248
6381
|
try {
|
|
6249
6382
|
const r = await confirmed(() => port.lists.restore(item, deletionId));
|
|
6250
|
-
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files.
|
|
6383
|
+
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files. Turn its fields on from the item.` });
|
|
6251
6384
|
onChanged();
|
|
6252
6385
|
return r;
|
|
6253
6386
|
} catch (e) {
|
|
@@ -6265,7 +6398,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6265
6398
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
|
|
6266
6399
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6267
6400
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "truncate text-sm text-foreground", children: item.name }),
|
|
6268
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "truncate text-xs text-muted-foreground", children:
|
|
6401
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
|
|
6269
6402
|
] }),
|
|
6270
6403
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_controls24.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6271
6404
|
] }, item.id)
|
|
@@ -6556,10 +6689,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6556
6689
|
title: "Send securely",
|
|
6557
6690
|
size: "md",
|
|
6558
6691
|
onClose,
|
|
6559
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
6560
|
-
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "w-full sm:w-auto sm:min-w-0 sm:flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(StatusLine, { error, notice }) }),
|
|
6692
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(StatusLine, { error, notice }) : null, children: [
|
|
6561
6693
|
sameChannelSent && !error ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Badge, { tone: "warning", children: "Both by email" }) : null,
|
|
6562
|
-
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Button, { variant: "quiet",
|
|
6694
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
6563
6695
|
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Button, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
|
|
6564
6696
|
] }),
|
|
6565
6697
|
children: [
|
|
@@ -7815,8 +7947,33 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7815
7947
|
},
|
|
7816
7948
|
[loc, move]
|
|
7817
7949
|
);
|
|
7950
|
+
const keyState = (0, import_react41.useRef)({ loc, go });
|
|
7951
|
+
keyState.current = { loc, go };
|
|
7952
|
+
(0, import_react41.useEffect)(() => {
|
|
7953
|
+
const onKey = (e) => {
|
|
7954
|
+
if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
7955
|
+
const root = rootRef.current;
|
|
7956
|
+
const at = document.activeElement;
|
|
7957
|
+
if (!root || at && at !== document.body && !root.contains(at)) return;
|
|
7958
|
+
if (at instanceof HTMLElement && (at.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(at.tagName))) return;
|
|
7959
|
+
if (document.querySelector('[role="dialog"], [role="alertdialog"]')) return;
|
|
7960
|
+
const { loc: here, go: to } = keyState.current;
|
|
7961
|
+
if (e.key === "/") {
|
|
7962
|
+
const search = root.querySelector('input[aria-label^="Search"]');
|
|
7963
|
+
if (!search) return;
|
|
7964
|
+
e.preventDefault();
|
|
7965
|
+
search.focus();
|
|
7966
|
+
} else if (e.key === "Escape" && here.itemId && here.mode === "view" && !here.panel) {
|
|
7967
|
+
e.preventDefault();
|
|
7968
|
+
to({ itemId: null, mode: "view", panel: null });
|
|
7969
|
+
}
|
|
7970
|
+
};
|
|
7971
|
+
document.addEventListener("keydown", onKey);
|
|
7972
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
7973
|
+
}, []);
|
|
7818
7974
|
const knobsRef = (0, import_react41.useRef)(host.knobs);
|
|
7819
7975
|
knobsRef.current = host.knobs;
|
|
7976
|
+
const [signedOut, setSignedOut] = (0, import_react41.useState)(false);
|
|
7820
7977
|
const load = (0, import_react41.useCallback)(() => {
|
|
7821
7978
|
setError(null);
|
|
7822
7979
|
port.load().then((s) => {
|
|
@@ -7827,7 +7984,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7827
7984
|
(rows) => setDeleted([...s.deleted, ...rows.filter((r) => !s.deleted.some((d) => d.id === r.id))]),
|
|
7828
7985
|
() => void 0
|
|
7829
7986
|
);
|
|
7830
|
-
}).catch((e) =>
|
|
7987
|
+
}).catch((e) => {
|
|
7988
|
+
setSignedOut(e?.status === 401);
|
|
7989
|
+
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
7990
|
+
});
|
|
7831
7991
|
port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
|
|
7832
7992
|
knobsRef.current?.().catch(() => void 0);
|
|
7833
7993
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
@@ -7841,6 +8001,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7841
8001
|
const orgs = snap?.organizations ?? [];
|
|
7842
8002
|
const definitions = snap?.definitions ?? [];
|
|
7843
8003
|
const inThisVault = (0, import_react41.useMemo)(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
|
|
8004
|
+
const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
7844
8005
|
const views = (0, import_react41.useMemo)(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
|
|
7845
8006
|
const visible = (0, import_react41.useMemo)(() => {
|
|
7846
8007
|
const filtered = inThisVault.filter((i) => {
|
|
@@ -7881,8 +8042,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7881
8042
|
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { ref: rootRef, role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 bg-background p-6 text-center text-sm", children: [
|
|
7882
8043
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
7883
8044
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
|
|
7884
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "max-w-xs text-muted-foreground", children: plainLoadError(error) }),
|
|
7885
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.
|
|
8045
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
|
|
8046
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex gap-2", children: [
|
|
8047
|
+
signedOut && host.signIn ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Button, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
|
|
8048
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Button, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
|
|
8049
|
+
] })
|
|
7886
8050
|
] });
|
|
7887
8051
|
}
|
|
7888
8052
|
if (!snap) {
|
|
@@ -7962,6 +8126,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7962
8126
|
{
|
|
7963
8127
|
title,
|
|
7964
8128
|
items: visible,
|
|
8129
|
+
showOwner: vaultMixesOwners,
|
|
7965
8130
|
definitions,
|
|
7966
8131
|
port,
|
|
7967
8132
|
selectedId: loc.itemId,
|
|
@@ -8363,6 +8528,7 @@ function createFieldsPort(ctx) {
|
|
|
8363
8528
|
if (patch.uriMatchMode !== void 0) body.uri_match_mode = patch.uriMatchMode;
|
|
8364
8529
|
if (patch.browserFillEnabled !== void 0) body.browser_fill_enabled = patch.browserFillEnabled;
|
|
8365
8530
|
if (patch.loginUrls !== void 0) body.login_urls = patch.loginUrls;
|
|
8531
|
+
if (patch.active !== void 0) body.status = patch.active ? "active" : "disabled";
|
|
8366
8532
|
await account3.updateItem(api, { path: { item_id: item.id }, body }, ctx.optsFor(item));
|
|
8367
8533
|
return reread(item);
|
|
8368
8534
|
},
|
|
@@ -8734,6 +8900,7 @@ async function readNativeImportLimits(api, organizationId) {
|
|
|
8734
8900
|
var recoveryOf = (w) => w.lifecycle?.vault_recovery;
|
|
8735
8901
|
var isDeleted = (w) => recoveryOf(w)?.state === "deleted";
|
|
8736
8902
|
var MATCH_MODES2 = ["host", "domain", "exact", "never"];
|
|
8903
|
+
var FIELD_WORDS = { totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
|
|
8737
8904
|
var handlingOf = (v) => v === "visible" || v === "sealed" ? v : "revealable";
|
|
8738
8905
|
function fieldOf(w, def) {
|
|
8739
8906
|
const declared = def?.fields.find((f) => f.key === w.field_key);
|
|
@@ -8741,7 +8908,7 @@ function fieldOf(w, def) {
|
|
|
8741
8908
|
return {
|
|
8742
8909
|
id: w.id,
|
|
8743
8910
|
key: w.field_key,
|
|
8744
|
-
label: declared?.label ?? humanize(w.field_key),
|
|
8911
|
+
label: declared?.label ?? FIELD_WORDS[w.field_key] ?? humanize(w.field_key),
|
|
8745
8912
|
kind: declared?.kind ?? (handling === "visible" ? "text" : "secret"),
|
|
8746
8913
|
handling,
|
|
8747
8914
|
editable: w.editable ?? true,
|
|
@@ -8774,6 +8941,7 @@ function itemOf(w, owner, defs, auth) {
|
|
|
8774
8941
|
uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
|
|
8775
8942
|
browserFillEnabled: w.browser_fill_enabled ?? true,
|
|
8776
8943
|
accessMode: w.access_mode ?? null,
|
|
8944
|
+
turnedOff: w.status === "disabled",
|
|
8777
8945
|
ownerUserId: w.user_id ?? null,
|
|
8778
8946
|
deletion: recovery?.state === "deleted" ? { deletionId: typeof recovery.deletion_id === "string" ? recovery.deletion_id : null, deletedAt: typeof recovery.deleted_at === "string" ? recovery.deleted_at : null } : null,
|
|
8779
8947
|
updatedAt: w.updated_at,
|
|
@@ -8833,9 +9001,12 @@ function createApiVaultPort(api, options = {}) {
|
|
|
8833
9001
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
8834
9002
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
8835
9003
|
const sharedP = retrying(() => account9.sharedWithMe(api));
|
|
9004
|
+
const quiet = (p) => void p.catch(() => void 0);
|
|
9005
|
+
[catalogP, authP, userP, sharedP].forEach(quiet);
|
|
8836
9006
|
const org = options.organizations ? null : await retrying(() => platform.listMyOrganizations(api));
|
|
8837
9007
|
orgs = [...new Map((options.organizations ?? (org?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
|
|
8838
9008
|
const orgListsP = orgs.map((o) => retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id })));
|
|
9009
|
+
orgListsP.forEach(quiet);
|
|
8839
9010
|
const [catalog, mine] = await Promise.all([catalogP, userP]);
|
|
8840
9011
|
const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
|
|
8841
9012
|
const unavailable = [];
|