@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.js
CHANGED
|
@@ -324,9 +324,20 @@ var FingerprintGlyph = glyph(/* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
|
324
324
|
var SendGlyph = glyph(/* @__PURE__ */ jsx2("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]);
|
|
325
325
|
|
|
326
326
|
// src/auth/identity.ts
|
|
327
|
+
var CONFIRM_RETURN_KEY = "matrx-vault:confirming-as";
|
|
328
|
+
var RETURN_WINDOW_MS = 15 * 6e4;
|
|
327
329
|
var SAME_PERSON = "That signed in a different account. Use the account this vault belongs to.";
|
|
328
330
|
function createSupabaseIdentity(auth, options = {}) {
|
|
329
331
|
let me = null;
|
|
332
|
+
const now = options.now ?? Date.now;
|
|
333
|
+
const store = () => {
|
|
334
|
+
if (options.store) return options.store;
|
|
335
|
+
try {
|
|
336
|
+
return globalThis.sessionStorage ?? null;
|
|
337
|
+
} catch {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
330
341
|
const who = async () => {
|
|
331
342
|
const { data } = await auth.getUser();
|
|
332
343
|
if (!data.user) throw new Error("You are signed out. Sign in again.");
|
|
@@ -343,10 +354,35 @@ function createSupabaseIdentity(auth, options = {}) {
|
|
|
343
354
|
return { email: u.email ?? null, providers: [...names].filter((p) => p !== "email" && p !== "phone"), hasPassword: names.has("email") };
|
|
344
355
|
},
|
|
345
356
|
async withProvider(provider) {
|
|
346
|
-
await who();
|
|
357
|
+
const u = await who();
|
|
358
|
+
store()?.setItem(CONFIRM_RETURN_KEY, JSON.stringify({ id: u.id, email: u.email ?? null, at: now() }));
|
|
347
359
|
const redirectTo = options.redirectTo?.() ?? globalThis.location?.href;
|
|
348
360
|
const { error } = await auth.signInWithOAuth({ provider, ...redirectTo ? { options: { redirectTo } } : {} });
|
|
349
|
-
if (error)
|
|
361
|
+
if (error) {
|
|
362
|
+
store()?.removeItem(CONFIRM_RETURN_KEY);
|
|
363
|
+
throw new Error(error.message);
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
async checkReturn() {
|
|
367
|
+
const s = store();
|
|
368
|
+
const raw = s?.getItem(CONFIRM_RETURN_KEY) ?? null;
|
|
369
|
+
if (!s || raw === null) return null;
|
|
370
|
+
s.removeItem(CONFIRM_RETURN_KEY);
|
|
371
|
+
let expected;
|
|
372
|
+
try {
|
|
373
|
+
expected = JSON.parse(raw);
|
|
374
|
+
} catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
if (typeof expected.id !== "string" || typeof expected.at !== "number" || now() - expected.at > RETURN_WINDOW_MS) return null;
|
|
378
|
+
const { data } = await auth.getUser();
|
|
379
|
+
if (!data.user || data.user.id === expected.id) return null;
|
|
380
|
+
const email = typeof expected.email === "string" && expected.email ? expected.email : null;
|
|
381
|
+
const message2 = `That signed in a different account, so it was signed out here.${email ? ` Sign in again as ${email}.` : " Sign in again."}`;
|
|
382
|
+
me = null;
|
|
383
|
+
if (options.onDifferentPerson) await options.onDifferentPerson(message2);
|
|
384
|
+
else await auth.signOut?.({ scope: "local" });
|
|
385
|
+
return message2;
|
|
350
386
|
},
|
|
351
387
|
async withPassword(password) {
|
|
352
388
|
const u = await who();
|
|
@@ -392,6 +428,18 @@ var providerLabel = (p) => PROVIDER_LABEL[p] ?? p.charAt(0).toUpperCase() + p.sl
|
|
|
392
428
|
function IdentityGate({ identity, children }) {
|
|
393
429
|
const [asking, setAsking] = useState2(false);
|
|
394
430
|
const waiters = useRef2([]);
|
|
431
|
+
const [returnProblem, setReturnProblem] = useState2(null);
|
|
432
|
+
useEffect2(() => {
|
|
433
|
+
if (!identity?.checkReturn) return;
|
|
434
|
+
let live = true;
|
|
435
|
+
identity.checkReturn().then(
|
|
436
|
+
(problem) => live && problem && setReturnProblem(problem),
|
|
437
|
+
(e) => live && setReturnProblem(e instanceof Error ? e.message : "The account that came back could not be checked.")
|
|
438
|
+
);
|
|
439
|
+
return () => {
|
|
440
|
+
live = false;
|
|
441
|
+
};
|
|
442
|
+
}, [identity]);
|
|
395
443
|
const confirmed = async (run) => {
|
|
396
444
|
try {
|
|
397
445
|
return await run();
|
|
@@ -412,7 +460,14 @@ function IdentityGate({ identity, children }) {
|
|
|
412
460
|
};
|
|
413
461
|
return /* @__PURE__ */ jsxs3(Ctx2.Provider, { value: confirmed, children: [
|
|
414
462
|
children,
|
|
415
|
-
identity ? /* @__PURE__ */ jsx3(ConfirmIdentityDialog, { open: asking, identity, onDone: () => settle(true), onCancel: () => settle(false) }) : null
|
|
463
|
+
identity ? /* @__PURE__ */ jsx3(ConfirmIdentityDialog, { open: asking, identity, onDone: () => settle(true), onCancel: () => settle(false) }) : null,
|
|
464
|
+
/* @__PURE__ */ jsx3(Dialog, { open: returnProblem !== null, onOpenChange: (o) => o ? void 0 : setReturnProblem(null), children: /* @__PURE__ */ jsxs3(DialogContent, { size: "sm", children: [
|
|
465
|
+
/* @__PURE__ */ jsxs3(DialogHeader, { children: [
|
|
466
|
+
/* @__PURE__ */ jsx3(DialogTitle, { children: "Different account" }),
|
|
467
|
+
/* @__PURE__ */ jsx3(DialogDescription, { children: returnProblem })
|
|
468
|
+
] }),
|
|
469
|
+
/* @__PURE__ */ jsx3("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx3(Button, { variant: "primary", onClick: () => setReturnProblem(null), children: "OK" }) })
|
|
470
|
+
] }) })
|
|
416
471
|
] });
|
|
417
472
|
}
|
|
418
473
|
var wasCancelled = (e) => e instanceof Error && e.message === CANCELLED;
|
|
@@ -476,7 +531,7 @@ function ConfirmIdentityDialog({ open, identity, onDone, onCancel }) {
|
|
|
476
531
|
e.preventDefault();
|
|
477
532
|
if (password) void attempt(() => identity.withPassword(password));
|
|
478
533
|
}, children: [
|
|
479
|
-
/* @__PURE__ */ jsx3(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) }),
|
|
534
|
+
/* @__PURE__ */ jsx3(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 }),
|
|
480
535
|
/* @__PURE__ */ jsx3(Button, { variant: "outline", type: "submit", disabled: busy || !password, children: "Confirm" })
|
|
481
536
|
] }) : null,
|
|
482
537
|
account10?.email ? codeSent ? /* @__PURE__ */ jsxs3("form", { className: "flex gap-2", onSubmit: (e) => {
|
|
@@ -604,6 +659,12 @@ function Panel({ title, open = true, onClose, children, footer, size = "lg" }) {
|
|
|
604
659
|
footer ? /* @__PURE__ */ jsx4(DialogFooter, { children: footer }) : null
|
|
605
660
|
] }) });
|
|
606
661
|
}
|
|
662
|
+
function PanelFooter({ status, children }) {
|
|
663
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex w-full flex-wrap items-center justify-end gap-2", children: [
|
|
664
|
+
status ? /* @__PURE__ */ jsx4("div", { className: "min-w-0 flex-1 basis-full sm:basis-0", children: status }) : null,
|
|
665
|
+
children
|
|
666
|
+
] });
|
|
667
|
+
}
|
|
607
668
|
var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
|
|
608
669
|
|
|
609
670
|
// src/FieldRows.tsx
|
|
@@ -614,7 +675,7 @@ function SecretText({ value, multiline }) {
|
|
|
614
675
|
return /* @__PURE__ */ jsx5("span", { className: "break-all font-mono text-sm tracking-wide", children: [...value].map((ch, i) => /* @__PURE__ */ jsx5("span", { className: /[0-9]/.test(ch) ? "text-primary" : /[^A-Za-z0-9]/.test(ch) ? "text-warning" : void 0, children: ch }, i)) });
|
|
615
676
|
}
|
|
616
677
|
var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
617
|
-
function SecretRow({ port, item, field, extra }) {
|
|
678
|
+
function SecretRow({ port, item, field, extra, onTurnOn }) {
|
|
618
679
|
const confirmed = useConfirmed();
|
|
619
680
|
const copyValue2 = useCopy();
|
|
620
681
|
const secret = useTransientSecret();
|
|
@@ -623,7 +684,7 @@ function SecretRow({ port, item, field, extra }) {
|
|
|
623
684
|
const [error, setError] = useState5(null);
|
|
624
685
|
const sealed = field.handling === "sealed";
|
|
625
686
|
const visible = field.handling === "visible";
|
|
626
|
-
const off = field.active === false;
|
|
687
|
+
const off = field.active === false || item.turnedOff === true;
|
|
627
688
|
const canSee = !sealed && !off && (visible ? item.capabilities.canUse : item.capabilities.canReveal);
|
|
628
689
|
useEffect5(() => {
|
|
629
690
|
if (!visible || !canSee) return;
|
|
@@ -668,10 +729,27 @@ function SecretRow({ port, item, field, extra }) {
|
|
|
668
729
|
top: multiline && shown !== null,
|
|
669
730
|
actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
670
731
|
extra,
|
|
732
|
+
off && onTurnOn ? /* @__PURE__ */ jsx5(TurnOnButton, { label: field.label, onTurnOn }) : null,
|
|
671
733
|
canSee && !visible ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: secret.value !== null ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": secret.value !== null ? `Hide ${field.label}` : `Show ${field.label}`, disabled: busy, onClick: () => void toggle2() }) : null,
|
|
672
734
|
canSee ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: /* @__PURE__ */ jsx5(CopyIcon, {}), "aria-label": `Copy ${field.label}`, disabled: busy, onClick: () => void copy() }) : null
|
|
673
735
|
] }),
|
|
674
|
-
children: sealed ? /* @__PURE__ */ jsx5(Badge, { icon: /* @__PURE__ */ jsx5(LockGlyph, {}), children: "
|
|
736
|
+
children: sealed ? /* @__PURE__ */ jsx5(Badge, { icon: /* @__PURE__ */ jsx5(LockGlyph, {}), children: "Never shown" }) : off ? /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: "Turned off" }) : error ? /* @__PURE__ */ jsx5("span", { className: "truncate text-destructive", title: error, children: error }) : shown !== null ? visible ? /* @__PURE__ */ jsx5("span", { className: cn3("block", multiline ? "whitespace-pre-wrap break-words" : "truncate"), children: shown || "\u2014" }) : /* @__PURE__ */ jsx5(SecretText, { value: shown, multiline }) : /* @__PURE__ */ jsx5("span", { className: cn3("block truncate text-muted-foreground", !visible && "tracking-widest"), children: visible ? "\u2026" : MASK })
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
function TurnOnButton({ label, onTurnOn }) {
|
|
741
|
+
const [busy, setBusy] = useState5(false);
|
|
742
|
+
return /* @__PURE__ */ jsx5(
|
|
743
|
+
Button2,
|
|
744
|
+
{
|
|
745
|
+
variant: "outline",
|
|
746
|
+
"aria-label": `Turn on ${label}`,
|
|
747
|
+
disabled: busy,
|
|
748
|
+
onClick: () => {
|
|
749
|
+
setBusy(true);
|
|
750
|
+
void onTurnOn().finally(() => setBusy(false));
|
|
751
|
+
},
|
|
752
|
+
children: "Turn on"
|
|
675
753
|
}
|
|
676
754
|
);
|
|
677
755
|
}
|
|
@@ -810,14 +888,27 @@ function loginSiteOf(item) {
|
|
|
810
888
|
return raw.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? "";
|
|
811
889
|
}
|
|
812
890
|
}
|
|
891
|
+
var TWO_PART_SUFFIX = /* @__PURE__ */ new Set(["co", "com", "org", "net", "gov", "edu", "ac", "ne", "or"]);
|
|
892
|
+
function siteDomainOf(host) {
|
|
893
|
+
const h = host.toLowerCase().replace(/\.$/, "");
|
|
894
|
+
if (!h || /^[\d.]+$/.test(h) || h.includes(":")) return h;
|
|
895
|
+
const labels = h.split(".").filter(Boolean);
|
|
896
|
+
if (labels.length <= 2) return labels.join(".");
|
|
897
|
+
const sld = labels[labels.length - 2] ?? "";
|
|
898
|
+
const tld = labels[labels.length - 1] ?? "";
|
|
899
|
+
const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
|
|
900
|
+
return labels.slice(-keep).join(".");
|
|
901
|
+
}
|
|
813
902
|
function sortItems(items, sort) {
|
|
814
903
|
const out = [...items];
|
|
815
904
|
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
816
905
|
if (sort === "name") return out.sort(byName);
|
|
817
|
-
if (sort === "website")
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
906
|
+
if (sort === "website")
|
|
907
|
+
return out.sort((a, b) => {
|
|
908
|
+
const x = loginSiteOf(a), y = loginSiteOf(b);
|
|
909
|
+
if (!x || !y) return x ? -1 : y ? 1 : byName(a, b);
|
|
910
|
+
return siteDomainOf(x).localeCompare(siteDomainOf(y)) || x.localeCompare(y) || byName(a, b);
|
|
911
|
+
});
|
|
821
912
|
if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
822
913
|
return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
823
914
|
}
|
|
@@ -1208,7 +1299,7 @@ import { useEffect as useEffect6, useRef as useRef4, useState as useState6 } fro
|
|
|
1208
1299
|
import { Button as Button3 } from "@ai-matrx/design-system/controls";
|
|
1209
1300
|
import { cn as cn4 } from "@ai-matrx/design-system";
|
|
1210
1301
|
import { formatAbsoluteDate } from "@ai-matrx/kit/format";
|
|
1211
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1302
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1212
1303
|
var PAGE = 50;
|
|
1213
1304
|
var MAX = 500;
|
|
1214
1305
|
function ActivityPanel({ item, port, onClose }) {
|
|
@@ -1237,7 +1328,10 @@ function ActivityPanel({ item, port, onClose }) {
|
|
|
1237
1328
|
{
|
|
1238
1329
|
title: "Activity",
|
|
1239
1330
|
onClose,
|
|
1240
|
-
footer:
|
|
1331
|
+
footer: /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1332
|
+
hasMore ? /* @__PURE__ */ jsx6(Button3, { variant: "outline", disabled: loading, onClick: () => setLimit((n) => Math.min(MAX, n * 2)), children: loading ? "Loading\u2026" : "Show more" }) : null,
|
|
1333
|
+
/* @__PURE__ */ jsx6(Button3, { variant: "primary", onClick: onClose, children: "Done" })
|
|
1334
|
+
] }),
|
|
1241
1335
|
children: [
|
|
1242
1336
|
error ? /* @__PURE__ */ jsx6("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
|
|
1243
1337
|
entries === null ? loading ? /* @__PURE__ */ jsx6(Empty, { children: "Reading activity\u2026" }) : null : entries.length === 0 ? /* @__PURE__ */ jsx6(Empty, { children: "Nothing has happened yet." }) : groupByDay(entries, now).map((day) => /* @__PURE__ */ jsx6(VaultSection, { title: day.label, children: collapseRuns(
|
|
@@ -1260,7 +1354,7 @@ function ActivityPanel({ item, port, onClose }) {
|
|
|
1260
1354
|
}
|
|
1261
1355
|
|
|
1262
1356
|
// src/activity/HistoryPanel.tsx
|
|
1263
|
-
import { Fragment as
|
|
1357
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1264
1358
|
var MASK2 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
1265
1359
|
var messageOf = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
1266
1360
|
function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
@@ -1320,8 +1414,11 @@ function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
|
1320
1414
|
{
|
|
1321
1415
|
title: "Password history",
|
|
1322
1416
|
onClose,
|
|
1323
|
-
footer:
|
|
1324
|
-
|
|
1417
|
+
footer: /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1418
|
+
page?.nextBefore ? /* @__PURE__ */ jsx7(Button4, { variant: "outline", disabled: more, onClick: () => void loadMore(), children: more ? "Loading\u2026" : "Show earlier" }) : null,
|
|
1419
|
+
/* @__PURE__ */ jsx7(Button4, { variant: "primary", onClick: onClose, children: "Done" })
|
|
1420
|
+
] }),
|
|
1421
|
+
children: !eligible ? /* @__PURE__ */ jsx7(Empty, { children: "History is kept only for your own items." }) : loading && !page ? /* @__PURE__ */ jsx7(Empty, { children: "Reading history\u2026" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1325
1422
|
error ? /* @__PURE__ */ jsx7("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
|
|
1326
1423
|
notice ? /* @__PURE__ */ jsx7("p", { role: "status", className: "px-1 text-sm text-success", children: notice }) : null,
|
|
1327
1424
|
page && groups.length === 0 ? /* @__PURE__ */ jsx7(Empty, { children: "No earlier values yet." }) : null,
|
|
@@ -1389,7 +1486,7 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
|
|
|
1389
1486
|
VaultRow,
|
|
1390
1487
|
{
|
|
1391
1488
|
label: when,
|
|
1392
|
-
actions: entry.available ? /* @__PURE__ */ jsxs7(
|
|
1489
|
+
actions: entry.available ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1393
1490
|
/* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: secret.value !== null ? /* @__PURE__ */ jsx7(EyeOffGlyph, {}) : /* @__PURE__ */ jsx7(EyeGlyph, {}), "aria-label": secret.value !== null ? "Hide" : "Show", disabled: busy, onClick: () => void toggle2() }),
|
|
1394
1491
|
/* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: /* @__PURE__ */ jsx7(CopyIcon2, {}), "aria-label": "Copy", disabled: busy, onClick: () => void copy() }),
|
|
1395
1492
|
canRestore(page, entry) ? /* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: /* @__PURE__ */ jsx7(RestoreGlyph, {}), "aria-label": "Restore", disabled: busy, onClick: () => void restore() }) : null
|
|
@@ -1723,7 +1820,7 @@ function imageFrom(data) {
|
|
|
1723
1820
|
}
|
|
1724
1821
|
|
|
1725
1822
|
// src/authenticator/Setup.tsx
|
|
1726
|
-
import { Fragment as
|
|
1823
|
+
import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1727
1824
|
function useCanScan() {
|
|
1728
1825
|
const [ok, setOk] = useState10(false);
|
|
1729
1826
|
useEffect10(() => {
|
|
@@ -1856,7 +1953,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1856
1953
|
VaultRow,
|
|
1857
1954
|
{
|
|
1858
1955
|
label,
|
|
1859
|
-
actions: /* @__PURE__ */ jsxs9(
|
|
1956
|
+
actions: /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1860
1957
|
/* @__PURE__ */ jsx9(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx9(QrGlyph, {}), "aria-label": "Choose QR image", title: "Choose or drop a QR image", disabled: disabled || reading, onClick: () => file.current?.click() }),
|
|
1861
1958
|
canScan ? /* @__PURE__ */ jsx9(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx9(CameraGlyph, {}), "aria-label": "Scan with camera", title: "Scan with camera", disabled, onClick: () => setScanning(true) }) : null
|
|
1862
1959
|
] }),
|
|
@@ -1925,13 +2022,14 @@ import { confirm as confirm2 } from "@ai-matrx/kit/confirm-opener";
|
|
|
1925
2022
|
|
|
1926
2023
|
// src/authenticator/port.ts
|
|
1927
2024
|
var MFA_METHOD_KEY = "mfa_method";
|
|
2025
|
+
var OTP_SEED_KEY = "totp_seed";
|
|
1928
2026
|
function mfaMethodOf(item) {
|
|
1929
2027
|
const v = item.custom.find((c) => c.key === MFA_METHOD_KEY)?.value;
|
|
1930
2028
|
return v === "sms" ? "sms" : v ? "push_or_other" : null;
|
|
1931
2029
|
}
|
|
1932
2030
|
|
|
1933
2031
|
// src/authenticator/TotpRows.tsx
|
|
1934
|
-
import { Fragment as
|
|
2032
|
+
import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1935
2033
|
function otpActionError(e, what) {
|
|
1936
2034
|
const status = e?.status;
|
|
1937
2035
|
if (status === 404) return "There is no one-time password here.";
|
|
@@ -2006,7 +2104,7 @@ function TotpRow({ port, item, onChanged }) {
|
|
|
2006
2104
|
VaultRow,
|
|
2007
2105
|
{
|
|
2008
2106
|
label: "One-time password",
|
|
2009
|
-
actions: /* @__PURE__ */ jsxs10(
|
|
2107
|
+
actions: /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
2010
2108
|
a.enabled ? /* @__PURE__ */ jsx10(CopyCodeButton, { live, label: item.name }) : null,
|
|
2011
2109
|
menu
|
|
2012
2110
|
] }),
|
|
@@ -2089,7 +2187,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
|
|
|
2089
2187
|
}
|
|
2090
2188
|
|
|
2091
2189
|
// src/authenticator/AddOtpPanel.tsx
|
|
2092
|
-
import { Fragment as
|
|
2190
|
+
import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2093
2191
|
var NEW = "__new__";
|
|
2094
2192
|
var LOGIN_KEYS = ["website_login", "username_password"];
|
|
2095
2193
|
function normalizeWebsite(raw) {
|
|
@@ -2172,7 +2270,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2172
2270
|
title: "Add one-time password",
|
|
2173
2271
|
size: "md",
|
|
2174
2272
|
onClose,
|
|
2175
|
-
footer: /* @__PURE__ */ jsxs11(
|
|
2273
|
+
footer: /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2176
2274
|
/* @__PURE__ */ jsx11(Button8, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2177
2275
|
/* @__PURE__ */ jsx11(Button8, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
|
|
2178
2276
|
] }),
|
|
@@ -2212,7 +2310,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2212
2310
|
}
|
|
2213
2311
|
}
|
|
2214
2312
|
) }),
|
|
2215
|
-
isNew ? /* @__PURE__ */ jsxs11(
|
|
2313
|
+
isNew ? /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2216
2314
|
/* @__PURE__ */ jsx11(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx11(
|
|
2217
2315
|
Field4,
|
|
2218
2316
|
{
|
|
@@ -2244,7 +2342,7 @@ function AddedPanel({ port, item, onClose, onDone }) {
|
|
|
2244
2342
|
}
|
|
2245
2343
|
|
|
2246
2344
|
// src/authenticator/AuthenticatorView.tsx
|
|
2247
|
-
import { Fragment as
|
|
2345
|
+
import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2248
2346
|
function matchesEntry(entry, q) {
|
|
2249
2347
|
if (!entry || !q) return false;
|
|
2250
2348
|
return [entry.issuer, entry.account].some((v) => v?.toLowerCase().includes(q));
|
|
@@ -2283,7 +2381,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2283
2381
|
const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
|
|
2284
2382
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
2285
2383
|
return /* @__PURE__ */ jsxs12("section", { "aria-label": "One-time passwords", className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
2286
|
-
header,
|
|
2384
|
+
header ? /* @__PURE__ */ jsx12("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
|
|
2287
2385
|
/* @__PURE__ */ jsxs12("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
|
|
2288
2386
|
/* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-baseline gap-2", children: [
|
|
2289
2387
|
/* @__PURE__ */ jsx12("h2", { className: "truncate text-sm font-semibold text-foreground", children: "One-time passwords" }),
|
|
@@ -2295,7 +2393,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2295
2393
|
/* @__PURE__ */ jsx12("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx12(ShieldGlyph, { className: "size-6" }) }),
|
|
2296
2394
|
/* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-foreground", children: "No one-time passwords yet" }),
|
|
2297
2395
|
/* @__PURE__ */ jsx12(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx12(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add one-time password" })
|
|
2298
|
-
] }) : groups.length === 0 ? /* @__PURE__ */ jsx12("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ jsx12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ jsx12(VaultSection, {
|
|
2396
|
+
] }) : groups.length === 0 ? /* @__PURE__ */ jsx12("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ jsx12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ jsx12(VaultSection, { title: g.label, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ jsx12(
|
|
2299
2397
|
OtpListRow,
|
|
2300
2398
|
{
|
|
2301
2399
|
port,
|
|
@@ -2392,7 +2490,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, on
|
|
|
2392
2490
|
/* @__PURE__ */ jsx12(CopyIcon4, { className: "size-4" }),
|
|
2393
2491
|
"Copy code"
|
|
2394
2492
|
] }) : null,
|
|
2395
|
-
canManage ? /* @__PURE__ */ jsxs12(
|
|
2493
|
+
canManage ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
|
|
2396
2494
|
/* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onRename, children: [
|
|
2397
2495
|
/* @__PURE__ */ jsx12(PencilGlyph, { className: "size-4" }),
|
|
2398
2496
|
"Rename"
|
|
@@ -2432,9 +2530,9 @@ function sandboxBlocker(envKeyDraft, savedEnvKey) {
|
|
|
2432
2530
|
return null;
|
|
2433
2531
|
}
|
|
2434
2532
|
var HANDLING_WORDS = {
|
|
2435
|
-
visible: { label: "
|
|
2436
|
-
revealable: { label: "
|
|
2437
|
-
sealed: { label: "
|
|
2533
|
+
visible: { label: "Always shown", hint: "Anyone who can use it can show or copy it" },
|
|
2534
|
+
revealable: { label: "Hidden", hint: "Showing or copying it needs reveal access" },
|
|
2535
|
+
sealed: { label: "Never shown", hint: "No one can see it. Automation can still use it." }
|
|
2438
2536
|
};
|
|
2439
2537
|
function handlingChoices(current) {
|
|
2440
2538
|
return current === "sealed" ? ["sealed"] : ["visible", "revealable", "sealed"];
|
|
@@ -2616,7 +2714,7 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2616
2714
|
}
|
|
2617
2715
|
) }),
|
|
2618
2716
|
/* @__PURE__ */ jsx13(VaultRow, { label: "Editable", hint: quietHint(field.editable ? "The value can be changed" : "The value is locked"), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Editable", checked: field.editable, disabled: locked, onCheckedChange: (v) => void update("editable", { editable: v }) }) }),
|
|
2619
|
-
/* @__PURE__ */ jsx13(VaultRow, { label: "
|
|
2717
|
+
/* @__PURE__ */ jsx13(VaultRow, { label: "Turned on", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Turned on", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: v }) }) })
|
|
2620
2718
|
] }),
|
|
2621
2719
|
error ? /* @__PURE__ */ jsx13(Problem, { children: error }) : null
|
|
2622
2720
|
] });
|
|
@@ -2684,7 +2782,7 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2684
2782
|
f.envKey
|
|
2685
2783
|
] }) : null,
|
|
2686
2784
|
f.injectIntoSandbox ? /* @__PURE__ */ jsx13("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
|
|
2687
|
-
!f.active ? /* @__PURE__ */ jsx13("span", { className: "text-
|
|
2785
|
+
!f.active ? /* @__PURE__ */ jsx13("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
|
|
2688
2786
|
] })
|
|
2689
2787
|
},
|
|
2690
2788
|
f.id
|
|
@@ -3080,7 +3178,7 @@ function startNewRestoreRun(preview) {
|
|
|
3080
3178
|
import { useState as useState16 } from "react";
|
|
3081
3179
|
import { Checkbox } from "@ai-matrx/design-system";
|
|
3082
3180
|
import { Badge as Badge4, Button as Button12, DisclosureHeader as DisclosureHeader2 } from "@ai-matrx/design-system/controls";
|
|
3083
|
-
import { Fragment as
|
|
3181
|
+
import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3084
3182
|
function PickLine({ checked, onChange, disabled = false, title, detail, badge, tone }) {
|
|
3085
3183
|
return /* @__PURE__ */ jsxs15("label", { className: "flex min-h-11 items-center gap-3 px-4 py-1", "data-clickable": disabled ? void 0 : "", children: [
|
|
3086
3184
|
/* @__PURE__ */ jsx15(Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
|
|
@@ -3092,7 +3190,7 @@ function PickLine({ checked, onChange, disabled = false, title, detail, badge, t
|
|
|
3092
3190
|
function Windowed({ items, size = 150, render }) {
|
|
3093
3191
|
const [all, setAll] = useState16(false);
|
|
3094
3192
|
const shown = all ? items : items.slice(0, size);
|
|
3095
|
-
return /* @__PURE__ */ jsxs15(
|
|
3193
|
+
return /* @__PURE__ */ jsxs15(Fragment9, { children: [
|
|
3096
3194
|
shown.map(render),
|
|
3097
3195
|
items.length > shown.length ? /* @__PURE__ */ jsx15("div", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs15(Button12, { variant: "quiet", onClick: () => setAll(true), children: [
|
|
3098
3196
|
"Show all ",
|
|
@@ -3113,7 +3211,7 @@ function ErrorLine({ message: message2 }) {
|
|
|
3113
3211
|
var plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
3114
3212
|
|
|
3115
3213
|
// src/io/BackupPanel.tsx
|
|
3116
|
-
import { Fragment as
|
|
3214
|
+
import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3117
3215
|
var RECORD_STATUS = {
|
|
3118
3216
|
created: "Restored",
|
|
3119
3217
|
replayed: "Already restored",
|
|
@@ -3241,13 +3339,13 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3241
3339
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3242
3340
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3243
3341
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3244
|
-
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(
|
|
3342
|
+
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3245
3343
|
/* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3246
3344
|
backup ? /* @__PURE__ */ jsx16(Button13, { variant: "primary", disabled: busy || !passphrase || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
|
|
3247
3345
|
"Review ",
|
|
3248
3346
|
selected.size
|
|
3249
3347
|
] })
|
|
3250
|
-
] }) : /* @__PURE__ */ jsxs16(
|
|
3348
|
+
] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3251
3349
|
/* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
|
|
3252
3350
|
result ? retryable ? /* @__PURE__ */ jsx16(Button13, { variant: "primary", disabled: busy, onClick: () => void restore(), children: "Try again" }) : /* @__PURE__ */ jsx16(Button13, { variant: "outline", disabled: busy, onClick: () => void again(), children: "Restore again" }) : restorePreview ? /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || restorePreview.omissions.length > 0 && !accepted, onClick: () => void restore(), children: [
|
|
3253
3351
|
"Restore ",
|
|
@@ -3268,12 +3366,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3268
3366
|
]
|
|
3269
3367
|
}
|
|
3270
3368
|
),
|
|
3271
|
-
mode === "backup" ? /* @__PURE__ */ jsxs16(
|
|
3369
|
+
mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3272
3370
|
/* @__PURE__ */ jsx16(
|
|
3273
3371
|
VaultSection,
|
|
3274
3372
|
{
|
|
3275
3373
|
title: `${selected.size} of ${plural(items.length, "credential")}`,
|
|
3276
|
-
actions: /* @__PURE__ */ jsxs16(
|
|
3374
|
+
actions: /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3277
3375
|
/* @__PURE__ */ jsx16(Button13, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
|
|
3278
3376
|
setBackup(null);
|
|
3279
3377
|
setSelected(new Set(items.map((i) => i.id)));
|
|
@@ -3286,7 +3384,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3286
3384
|
children: items.length === 0 ? /* @__PURE__ */ jsx16(Empty, { children: "Nothing to back up yet." }) : /* @__PURE__ */ jsx16(Windowed, { items, render: (i) => /* @__PURE__ */ jsx16(PickLine, { title: i.name, detail: i.definitionLabel, checked: selected.has(i.id), disabled: busy, onChange: (on) => pick(i.id, on) }, i.id) })
|
|
3287
3385
|
}
|
|
3288
3386
|
),
|
|
3289
|
-
backup ? /* @__PURE__ */ jsxs16(
|
|
3387
|
+
backup ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3290
3388
|
/* @__PURE__ */ jsx16(Summary, { value: backup }),
|
|
3291
3389
|
/* @__PURE__ */ jsx16(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3292
3390
|
/* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
@@ -3294,7 +3392,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3294
3392
|
/* @__PURE__ */ jsx16(VaultRow, { label: "Repeat", ...mismatch ? { hint: "Doesn't match" } : {}, children: /* @__PURE__ */ jsx16(Field6, { type: "password", value: repeat, autoComplete: "new-password", "aria-label": "Repeat the passphrase", onChange: (e) => setRepeat(e.target.value) }) })
|
|
3295
3393
|
] })
|
|
3296
3394
|
] }) : null
|
|
3297
|
-
] }) : /* @__PURE__ */ jsx16(
|
|
3395
|
+
] }) : /* @__PURE__ */ jsx16(Fragment10, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3298
3396
|
/* @__PURE__ */ jsxs16(VaultRow, { label: "File", ...file ? { hint: file.name } : {}, children: [
|
|
3299
3397
|
/* @__PURE__ */ jsx16(Button13, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
|
|
3300
3398
|
/* @__PURE__ */ jsx16(
|
|
@@ -3312,7 +3410,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3312
3410
|
)
|
|
3313
3411
|
] }),
|
|
3314
3412
|
/* @__PURE__ */ jsx16(VaultRow, { label: "Passphrase", children: /* @__PURE__ */ jsx16(Field6, { type: "password", value: passphrase, autoComplete: "current-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) })
|
|
3315
|
-
] }) : /* @__PURE__ */ jsxs16(
|
|
3413
|
+
] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3316
3414
|
/* @__PURE__ */ jsx16(Summary, { value: restorePreview }),
|
|
3317
3415
|
!result ? /* @__PURE__ */ jsx16(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
|
|
3318
3416
|
!result ? /* @__PURE__ */ jsx16("p", { className: "px-1 text-xs text-muted-foreground", children: "Restored items start disabled and restricted." }) : /* @__PURE__ */ jsx16(VaultSection, { title: `${result.created} restored \xB7 ${result.replayed} already \xB7 ${result.refused} refused \xB7 ${result.retryable_failure} to retry`, children: result.results.map((r) => /* @__PURE__ */ jsx16(VaultRow, { label: names.get(r.source_item_id) ?? "Credential", children: /* @__PURE__ */ jsxs16("span", { className: r.status === "refused" || r.status === "retryable_failure" ? "text-destructive" : "text-foreground", children: [
|
|
@@ -3329,7 +3427,7 @@ import { useMemo, useState as useState18 } from "react";
|
|
|
3329
3427
|
import { Button as Button14, Select as Select5 } from "@ai-matrx/design-system/controls";
|
|
3330
3428
|
import { downloadFile as downloadFile2 } from "@ai-matrx/kit/download";
|
|
3331
3429
|
import { confirm as confirm5 } from "@ai-matrx/kit/confirm-opener";
|
|
3332
|
-
import { Fragment as
|
|
3430
|
+
import { Fragment as Fragment11, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3333
3431
|
var FORMATS = [
|
|
3334
3432
|
{ value: "matrx_login_csv_v1", label: "Matrx", hint: "Website logins, all common fields" },
|
|
3335
3433
|
{ value: "firefox_csv_v1", label: "Firefox", hint: "Address, username and password" },
|
|
@@ -3409,7 +3507,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3409
3507
|
title: "Export logins",
|
|
3410
3508
|
size: "lg",
|
|
3411
3509
|
onClose,
|
|
3412
|
-
footer: /* @__PURE__ */ jsxs17(
|
|
3510
|
+
footer: /* @__PURE__ */ jsxs17(Fragment11, { children: [
|
|
3413
3511
|
/* @__PURE__ */ jsx17(Button14, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3414
3512
|
preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */ jsx17(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
|
|
3415
3513
|
"Download ",
|
|
@@ -3436,7 +3534,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3436
3534
|
VaultSection,
|
|
3437
3535
|
{
|
|
3438
3536
|
title: `${selected.size} of ${plural(logins.length, "login")}`,
|
|
3439
|
-
actions: /* @__PURE__ */ jsxs17(
|
|
3537
|
+
actions: /* @__PURE__ */ jsxs17(Fragment11, { children: [
|
|
3440
3538
|
/* @__PURE__ */ jsx17(Button14, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
|
|
3441
3539
|
changed();
|
|
3442
3540
|
setSelected(new Set(logins.map((l) => l.id)));
|
|
@@ -4318,7 +4416,7 @@ async function parseImportFile(source, file, limits, signal) {
|
|
|
4318
4416
|
}
|
|
4319
4417
|
|
|
4320
4418
|
// src/io/ImportPanel.tsx
|
|
4321
|
-
import { Fragment as
|
|
4419
|
+
import { Fragment as Fragment12, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4322
4420
|
var ROLE_OPTIONS = [
|
|
4323
4421
|
{ value: "keep", label: "Keep encrypted" },
|
|
4324
4422
|
{ value: "title", label: "Name" },
|
|
@@ -4493,13 +4591,13 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4493
4591
|
const help = EXPORT_HELP[source];
|
|
4494
4592
|
const stage = done ? "done" : draft ? "review" : "choose";
|
|
4495
4593
|
const busy = running !== null || reading;
|
|
4496
|
-
const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(
|
|
4594
|
+
const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4497
4595
|
/* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
4498
4596
|
source === "env" ? /* @__PURE__ */ jsx18(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx18(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
|
|
4499
|
-
] }) : stage === "review" ? /* @__PURE__ */ jsxs18(
|
|
4597
|
+
] }) : stage === "review" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4500
4598
|
running ? /* @__PURE__ */ jsx18(Button15, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: reset, children: "Back" }),
|
|
4501
4599
|
/* @__PURE__ */ jsx18(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx18(ImportGlyph, { className: "size-4" }), disabled: busy || chosen === 0 || ambiguous === true || needsApproval, onClick: start, children: running ? `Importing ${running.done} of ${running.total}` : `Import ${chosen}` })
|
|
4502
|
-
] }) : /* @__PURE__ */ jsxs18(
|
|
4600
|
+
] }) : /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4503
4601
|
done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */ jsx18(Button15, { variant: "outline", disabled: busy, onClick: retry, children: running ? `Importing ${running.done} of ${running.total}` : `Try ${done.failed.length + done.untried.length} again` }) : null,
|
|
4504
4602
|
/* @__PURE__ */ jsx18(Button15, { variant: "primary", onClick: onClose, children: "Done" })
|
|
4505
4603
|
] });
|
|
@@ -4529,13 +4627,13 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4529
4627
|
] }),
|
|
4530
4628
|
source === "env" ? /* @__PURE__ */ jsx18(VaultRow, { label: "Sandboxes", hint: "Pass these values to agent sandboxes", children: /* @__PURE__ */ jsx18(Switch4, { checked: injectSandbox, onCheckedChange: setInjectSandbox, "aria-label": "Use in sandboxes" }) }) : null
|
|
4531
4629
|
] }) : null,
|
|
4532
|
-
stage === "review" && draft ? /* @__PURE__ */ jsxs18(
|
|
4630
|
+
stage === "review" && draft ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4533
4631
|
organizations.length > 0 ? /* @__PURE__ */ jsx18(VaultSection, { children: /* @__PURE__ */ jsx18(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx18(Select6, { value: destination, options: destinationOptions, "aria-label": "Save to", onValueChange: (v) => draft.kind === "file" ? restart({ destination: v }) : setDestination(v) }) }) }) : null,
|
|
4534
4632
|
/* @__PURE__ */ jsx18(
|
|
4535
4633
|
VaultSection,
|
|
4536
4634
|
{
|
|
4537
4635
|
title: draft.kind === "env" ? plural(envKeys.length, "value") : summary(counts, lines.length),
|
|
4538
|
-
actions: /* @__PURE__ */ jsxs18(
|
|
4636
|
+
actions: /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4539
4637
|
/* @__PURE__ */ jsx18(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(draft.kind === "env" ? new Set(envKeys.map((e) => e.key + e.text)) : defaultSelection(lines)), children: "Reset" }),
|
|
4540
4638
|
/* @__PURE__ */ jsx18(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
|
|
4541
4639
|
] }),
|
|
@@ -4629,7 +4727,7 @@ import { jsx as jsx19 } from "react/jsx-runtime";
|
|
|
4629
4727
|
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
4630
4728
|
const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
|
|
4631
4729
|
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
4632
|
-
const initial = site
|
|
4730
|
+
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
4633
4731
|
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
4634
4732
|
return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
4635
4733
|
}
|
|
@@ -4652,13 +4750,13 @@ import { cn as cn9 } from "@ai-matrx/design-system";
|
|
|
4652
4750
|
import { confirm as confirm6 } from "@ai-matrx/kit/confirm-opener";
|
|
4653
4751
|
import { downloadFile as downloadFile3 } from "@ai-matrx/kit/download";
|
|
4654
4752
|
import { DownloadIcon } from "@ai-matrx/design-system/icons";
|
|
4655
|
-
import { Fragment as
|
|
4753
|
+
import { Fragment as Fragment13, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4656
4754
|
var messageOf2 = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
4657
4755
|
var TOO_BIG = "Files over 25 MB can't be stored.";
|
|
4658
4756
|
var PROTECTION = [
|
|
4659
4757
|
{ value: "visible", label: "Open", title: "Anyone who can use the item can download it" },
|
|
4660
4758
|
{ value: "revealable", label: "Protected", title: "Downloading needs a recent sign-in" },
|
|
4661
|
-
{ value: "sealed", label: "
|
|
4759
|
+
{ value: "sealed", label: "Never shown", title: "Only automation can use it, never a person" }
|
|
4662
4760
|
];
|
|
4663
4761
|
function FilesSection({ item, port, editing, onChanged }) {
|
|
4664
4762
|
const confirmed = useConfirmed();
|
|
@@ -4725,7 +4823,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4725
4823
|
{
|
|
4726
4824
|
label: a.label,
|
|
4727
4825
|
hint: a.description || void 0,
|
|
4728
|
-
actions: a.handling === "sealed" ? /* @__PURE__ */ jsx20(Badge5, { icon: /* @__PURE__ */ jsx20(LockGlyph, {}), children: "
|
|
4826
|
+
actions: a.handling === "sealed" ? /* @__PURE__ */ jsx20(Badge5, { icon: /* @__PURE__ */ jsx20(LockGlyph, {}), children: "Never shown" }) : canDownload(item, a) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: busy !== null, onClick: () => void download(a) }) : null,
|
|
4729
4827
|
children: /* @__PURE__ */ jsx20(FileName, { file: a })
|
|
4730
4828
|
},
|
|
4731
4829
|
a.id
|
|
@@ -4749,13 +4847,13 @@ function EditableFile({ port, item: it, file: a, busy: b, run: go, onDownload, o
|
|
|
4749
4847
|
const yes = await confirm6({ title: `Delete ${a.label}?`, description: "The encrypted file is removed from this item.", confirmLabel: "Delete", variant: "destructive" });
|
|
4750
4848
|
if (yes) await go(`delete:${a.id}`, () => port.activity.deleteFile(it, a.id), "The file could not be deleted.");
|
|
4751
4849
|
}
|
|
4752
|
-
return /* @__PURE__ */ jsxs19(
|
|
4850
|
+
return /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4753
4851
|
/* @__PURE__ */ jsx20(
|
|
4754
4852
|
VaultRow,
|
|
4755
4853
|
{
|
|
4756
4854
|
label: a.label,
|
|
4757
4855
|
hint: a.description || void 0,
|
|
4758
|
-
actions: /* @__PURE__ */ jsxs19(
|
|
4856
|
+
actions: /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4759
4857
|
canDownload(it, a) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: b !== null, onClick: onDownload }) : null,
|
|
4760
4858
|
/* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PencilGlyph, {}), "aria-label": `Edit ${a.label}`, pressed: open, disabled: b !== null, onClick: () => setOpen((o) => !o) }),
|
|
4761
4859
|
/* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(UploadGlyph, {}), "aria-label": `Replace ${a.fileName}`, disabled: b !== null, onClick: () => replacer.current?.click() }),
|
|
@@ -4809,7 +4907,7 @@ function NewFile({ file, busy, onAdd, onCancel }) {
|
|
|
4809
4907
|
if (handling === "sealed" && !await confirmSeal(label)) return;
|
|
4810
4908
|
await onAdd({ label: label.trim(), description: description.trim() || null, handling });
|
|
4811
4909
|
}
|
|
4812
|
-
return /* @__PURE__ */ jsxs19(
|
|
4910
|
+
return /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4813
4911
|
/* @__PURE__ */ jsx20(VaultRow, { label: "New file", children: /* @__PURE__ */ jsxs19("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
4814
4912
|
/* @__PURE__ */ jsx20("span", { className: "truncate", children: file.name }),
|
|
4815
4913
|
/* @__PURE__ */ jsx20("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize2(file.size) })
|
|
@@ -4833,7 +4931,7 @@ function FileDetailsRows({ file, busy, onSave, onCancel }) {
|
|
|
4833
4931
|
if (handling === "sealed" && file.handling !== "sealed" && !await confirmSeal(label)) return;
|
|
4834
4932
|
await onSave({ label: label.trim(), description: description.trim() || null, fileName: fileName.trim(), handling });
|
|
4835
4933
|
}
|
|
4836
|
-
return /* @__PURE__ */ jsxs19(
|
|
4934
|
+
return /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4837
4935
|
/* @__PURE__ */ jsx20(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "Name", value: label, onChange: (e) => setLabel(e.target.value) }) }),
|
|
4838
4936
|
/* @__PURE__ */ jsx20(VaultRow, { label: "Purpose", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "Purpose", placeholder: "What it is for", value: description, onChange: (e) => setDescription(e.target.value) }) }),
|
|
4839
4937
|
/* @__PURE__ */ jsx20(VaultRow, { label: "File name", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "File name", value: fileName, onChange: (e) => setFileName(e.target.value) }) }),
|
|
@@ -4857,7 +4955,7 @@ function confirmSeal(label) {
|
|
|
4857
4955
|
import { useState as useState21 } from "react";
|
|
4858
4956
|
import { Badge as Badge6, Button as Button17, Textarea as Textarea3 } from "@ai-matrx/design-system/controls";
|
|
4859
4957
|
import { CopyIcon as CopyIcon6 } from "@ai-matrx/design-system/icons";
|
|
4860
|
-
import { Fragment as
|
|
4958
|
+
import { Fragment as Fragment14, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4861
4959
|
var MASK4 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
4862
4960
|
var say2 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
4863
4961
|
function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
@@ -4901,7 +4999,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
4901
4999
|
{
|
|
4902
5000
|
label: "Recovery codes",
|
|
4903
5001
|
top: true,
|
|
4904
|
-
actions: /* @__PURE__ */ jsxs20(
|
|
5002
|
+
actions: /* @__PURE__ */ jsxs20(Fragment14, { children: [
|
|
4905
5003
|
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CheckGlyph, {}), "aria-label": "Save codes", disabled: busy || !draft.trim(), onClick: () => void saveDraft() }),
|
|
4906
5004
|
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx21(XGlyph, {}), "aria-label": "Cancel", disabled: busy, onClick: () => {
|
|
4907
5005
|
setDraft(null);
|
|
@@ -4943,11 +5041,11 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
4943
5041
|
{
|
|
4944
5042
|
label: "Recovery codes",
|
|
4945
5043
|
top: codes !== null,
|
|
4946
|
-
actions: /* @__PURE__ */ jsxs20(
|
|
5044
|
+
actions: /* @__PURE__ */ jsxs20(Fragment14, { children: [
|
|
4947
5045
|
canSee ? /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: codes ? /* @__PURE__ */ jsx21(EyeOffGlyph, {}) : /* @__PURE__ */ jsx21(EyeGlyph, {}), "aria-label": codes ? "Hide codes" : "Show codes", disabled: busy, onClick: () => void toggle2() }) : null,
|
|
4948
5046
|
canEdit && !sealed ? /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(PencilGlyph, {}), "aria-label": "Replace all codes", disabled: busy, onClick: () => setDraft("") }) : null
|
|
4949
5047
|
] }),
|
|
4950
|
-
children: sealed ? /* @__PURE__ */ jsx21(Badge6, { icon: /* @__PURE__ */ jsx21(LockGlyph, {}), children: "
|
|
5048
|
+
children: sealed ? /* @__PURE__ */ jsx21(Badge6, { icon: /* @__PURE__ */ jsx21(LockGlyph, {}), children: "Never shown" }) : codes ? /* @__PURE__ */ jsxs20("ul", { className: "flex flex-col gap-0.5", "aria-label": "Recovery codes", children: [
|
|
4951
5049
|
codes.map((code, i) => /* @__PURE__ */ jsxs20("li", { className: "flex min-h-7 items-center gap-1", children: [
|
|
4952
5050
|
/* @__PURE__ */ jsx21("code", { className: "min-w-0 flex-1 break-all font-mono text-sm text-foreground", children: code }),
|
|
4953
5051
|
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CopyIcon6, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue2(code, "Recovery code") }),
|
|
@@ -5270,10 +5368,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5270
5368
|
title: "Move or copy",
|
|
5271
5369
|
size: "md",
|
|
5272
5370
|
onClose,
|
|
5273
|
-
footer: /* @__PURE__ */
|
|
5274
|
-
/* @__PURE__ */ jsx24(StatusLine, { error, notice }),
|
|
5275
|
-
/* @__PURE__ */ jsx24(Button19, { variant: "outline", className: "ml-auto", onClick: onClose, children: "Close" })
|
|
5276
|
-
] }),
|
|
5371
|
+
footer: /* @__PURE__ */ jsx24(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx24(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx24(Button19, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5277
5372
|
children: nothing ? /* @__PURE__ */ jsx24(VaultSection, { children: /* @__PURE__ */ jsx24(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ jsxs22(VaultSection, { children: [
|
|
5278
5373
|
canMove && moves.length > 0 ? /* @__PURE__ */ jsx24(
|
|
5279
5374
|
VaultRow,
|
|
@@ -5305,7 +5400,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5305
5400
|
}
|
|
5306
5401
|
|
|
5307
5402
|
// src/sharing/SharePanel.tsx
|
|
5308
|
-
import { Fragment as
|
|
5403
|
+
import { Fragment as Fragment15, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
5309
5404
|
function useGrants(port, item) {
|
|
5310
5405
|
const [grants, setGrants] = useState25(null);
|
|
5311
5406
|
const [loadError, setLoadError] = useState25(null);
|
|
@@ -5388,10 +5483,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5388
5483
|
title: "Share",
|
|
5389
5484
|
size: "md",
|
|
5390
5485
|
onClose,
|
|
5391
|
-
footer: /* @__PURE__ */
|
|
5392
|
-
/* @__PURE__ */ jsx25(StatusLine, { error, notice }),
|
|
5393
|
-
/* @__PURE__ */ jsx25(Button20, { variant: "primary", className: "ml-auto", onClick: onClose, children: "Done" })
|
|
5394
|
-
] }),
|
|
5486
|
+
footer: /* @__PURE__ */ jsx25(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx25(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5395
5487
|
children: [
|
|
5396
5488
|
/* @__PURE__ */ jsxs23(VaultSection, { title: "Who has access", children: [
|
|
5397
5489
|
isOrg ? /* @__PURE__ */ jsx25(AccessLine, { glyph: BuildingGlyph, who: `${orgName} admins`, children: /* @__PURE__ */ jsx25("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }) : /* @__PURE__ */ jsx25(AccessLine, { glyph: PersonGlyph, who: "You", meta: "Owner", children: /* @__PURE__ */ jsx25("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }),
|
|
@@ -5456,7 +5548,7 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
|
5456
5548
|
const [level, setLevel] = useState25("use");
|
|
5457
5549
|
const chosen = open.find((o) => o.id === target);
|
|
5458
5550
|
if (item.owner.kind !== "me") return null;
|
|
5459
|
-
return /* @__PURE__ */ jsx25(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs23(
|
|
5551
|
+
return /* @__PURE__ */ jsx25(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs23(Fragment15, { children: [
|
|
5460
5552
|
/* @__PURE__ */ jsxs23("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5461
5553
|
/* @__PURE__ */ jsx25(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5462
5554
|
/* @__PURE__ */ jsx25(Select8, { className: "min-w-0 flex-1", "aria-label": "Organization", value: target || "__none__", onValueChange: (v) => setTarget(v === "__none__" ? "" : v), options: [{ value: "__none__", label: "Choose an organization" }, ...open.map((o) => ({ value: o.id, label: o.name }))] }),
|
|
@@ -5542,7 +5634,7 @@ function SharingSummary({ item, port, className }) {
|
|
|
5542
5634
|
|
|
5543
5635
|
// src/ItemPane.tsx
|
|
5544
5636
|
import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
|
|
5545
|
-
import { Fragment as
|
|
5637
|
+
import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5546
5638
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5547
5639
|
function ItemPane(props) {
|
|
5548
5640
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
@@ -5677,6 +5769,27 @@ function ItemPane(props) {
|
|
|
5677
5769
|
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "The value could not be read.");
|
|
5678
5770
|
}
|
|
5679
5771
|
}
|
|
5772
|
+
const offFields = item ? item.fields.filter((f) => !f.active) : [];
|
|
5773
|
+
const itemOff = item?.turnedOff === true;
|
|
5774
|
+
const seedField = item?.fields.find((f) => f.key === OTP_SEED_KEY) ?? null;
|
|
5775
|
+
const canTurnOn = Boolean(item && canEdit);
|
|
5776
|
+
async function turnOn(fields) {
|
|
5777
|
+
if (!item) return;
|
|
5778
|
+
setError(null);
|
|
5779
|
+
try {
|
|
5780
|
+
if (item.turnedOff) await confirmed(() => port.fields.updateItem(item, { active: true }));
|
|
5781
|
+
for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
|
|
5782
|
+
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
5783
|
+
const codes = await port.authenticator.get(item);
|
|
5784
|
+
if (codes && !codes.enabled) await confirmed(() => port.authenticator.setEnabled(item, true));
|
|
5785
|
+
}
|
|
5786
|
+
onChanged();
|
|
5787
|
+
} catch (e) {
|
|
5788
|
+
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
|
|
5789
|
+
onChanged();
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
5680
5793
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
5681
5794
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
5682
5795
|
const metaValue = (key) => draft.values[key] ?? item?.custom.find((c) => c.key === key)?.value ?? "";
|
|
@@ -5685,6 +5798,10 @@ function ItemPane(props) {
|
|
|
5685
5798
|
const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
|
|
5686
5799
|
const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
|
|
5687
5800
|
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ jsx26(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ jsx26(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ jsx26(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ jsx26(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ jsx26(BuildingGlyph, {}) : /* @__PURE__ */ jsx26(UsersIcon2, {}) } : null;
|
|
5801
|
+
const sameNamed = (id) => {
|
|
5802
|
+
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
5803
|
+
return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
|
|
5804
|
+
};
|
|
5688
5805
|
const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
|
|
5689
5806
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5690
5807
|
const header = /* @__PURE__ */ jsxs24("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: [
|
|
@@ -5752,7 +5869,7 @@ function ItemPane(props) {
|
|
|
5752
5869
|
/* @__PURE__ */ jsx26(SettingsIcon, { className: "size-4" }),
|
|
5753
5870
|
"Settings"
|
|
5754
5871
|
] }) : null,
|
|
5755
|
-
canManage ? /* @__PURE__ */ jsxs24(
|
|
5872
|
+
canManage ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5756
5873
|
/* @__PURE__ */ jsx26(DropdownMenuSeparator3, {}),
|
|
5757
5874
|
/* @__PURE__ */ jsxs24(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
|
|
5758
5875
|
/* @__PURE__ */ jsx26(TrashGlyph, { className: "size-4" }),
|
|
@@ -5768,7 +5885,11 @@ function ItemPane(props) {
|
|
|
5768
5885
|
header,
|
|
5769
5886
|
error ? /* @__PURE__ */ jsx26("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
|
|
5770
5887
|
notice && !editing ? /* @__PURE__ */ jsx26("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
|
|
5771
|
-
|
|
5888
|
+
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ jsxs24("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
|
|
5889
|
+
/* @__PURE__ */ jsx26("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` }),
|
|
5890
|
+
canTurnOn ? /* @__PURE__ */ jsx26(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
5891
|
+
] }) : null,
|
|
5892
|
+
/* @__PURE__ */ jsx26("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx26("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__ */ jsxs24(Fragment16, { children: [
|
|
5772
5893
|
/* @__PURE__ */ jsxs24(VaultSection, { children: [
|
|
5773
5894
|
mode === "new" ? /* @__PURE__ */ jsx26(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx26(
|
|
5774
5895
|
OptionCombobox,
|
|
@@ -5780,16 +5901,16 @@ function ItemPane(props) {
|
|
|
5780
5901
|
searchPlaceholder: "Find an organization",
|
|
5781
5902
|
groups: [
|
|
5782
5903
|
{ heading: "Just you", options: ["me"] },
|
|
5783
|
-
...organizations.length > 0 ? [{ heading: "Organizations", options: organizations.map((o) => o.id) }] : [],
|
|
5904
|
+
...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) }] : [],
|
|
5784
5905
|
{ heading: "Send", options: ["person"] }
|
|
5785
5906
|
],
|
|
5786
5907
|
getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
|
|
5787
|
-
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : null,
|
|
5908
|
+
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
|
|
5788
5909
|
renderIcon: (v) => v === "me" ? /* @__PURE__ */ jsx26(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ jsx26(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ jsx26(BuildingGlyph, { className: "size-4" })
|
|
5789
5910
|
}
|
|
5790
5911
|
) }) : null,
|
|
5791
5912
|
/* @__PURE__ */ jsx26(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
|
|
5792
|
-
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(
|
|
5913
|
+
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5793
5914
|
/* @__PURE__ */ jsx26(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
|
|
5794
5915
|
declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ jsx26(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ jsx26(Switch5, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
|
|
5795
5916
|
] }) : null,
|
|
@@ -5808,7 +5929,7 @@ function ItemPane(props) {
|
|
|
5808
5929
|
multiline: f.kind === "multiline",
|
|
5809
5930
|
inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
|
|
5810
5931
|
onChange: (v) => setValue(f.key, v),
|
|
5811
|
-
actions: /* @__PURE__ */ jsxs24(
|
|
5932
|
+
actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5812
5933
|
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
5813
5934
|
secretKind ? /* @__PURE__ */ jsx26(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
|
|
5814
5935
|
existing ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
|
|
@@ -5827,7 +5948,7 @@ function ItemPane(props) {
|
|
|
5827
5948
|
onChange: (v) => setValue(f.key, v),
|
|
5828
5949
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
5829
5950
|
removeLabel: `Delete ${f.label}`,
|
|
5830
|
-
actions: /* @__PURE__ */ jsxs24(
|
|
5951
|
+
actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5831
5952
|
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
5832
5953
|
/* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
|
|
5833
5954
|
] })
|
|
@@ -5859,7 +5980,7 @@ function ItemPane(props) {
|
|
|
5859
5980
|
i
|
|
5860
5981
|
)),
|
|
5861
5982
|
/* @__PURE__ */ jsx26(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
5862
|
-
/* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator), item, port, onEnrolled: onChanged }),
|
|
5983
|
+
/* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
5863
5984
|
item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
5864
5985
|
] }),
|
|
5865
5986
|
/* @__PURE__ */ jsx26(VaultSection, { children: /* @__PURE__ */ jsx26(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
|
|
@@ -5892,12 +6013,12 @@ function ItemPane(props) {
|
|
|
5892
6013
|
) : null,
|
|
5893
6014
|
draft.secrets.map((s, i) => /* @__PURE__ */ jsx26(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}`)),
|
|
5894
6015
|
extraCustom.map((c) => /* @__PURE__ */ jsx26(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)),
|
|
5895
|
-
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "
|
|
6016
|
+
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
|
|
5896
6017
|
]
|
|
5897
6018
|
}
|
|
5898
6019
|
),
|
|
5899
6020
|
filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: true }) : null
|
|
5900
|
-
] }) : item ? /* @__PURE__ */ jsxs24(
|
|
6021
|
+
] }) : item ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5901
6022
|
/* @__PURE__ */ jsxs24(VaultSection, { children: [
|
|
5902
6023
|
declared.map((f) => {
|
|
5903
6024
|
if (f.storage === "metadata") {
|
|
@@ -5906,11 +6027,15 @@ function ItemPane(props) {
|
|
|
5906
6027
|
}
|
|
5907
6028
|
const field = item.fields.find((x) => x.key === f.key);
|
|
5908
6029
|
if (isRecoveryCodesField(f)) return /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
|
|
5909
|
-
return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field }, field.id) : null;
|
|
6030
|
+
return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field, onTurnOn: turnOnOne(field) }, field.id) : null;
|
|
5910
6031
|
}),
|
|
5911
|
-
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx26(SecretRow, { port, item, field: f }, f.id)),
|
|
6032
|
+
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx26(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f) }, f.id)),
|
|
5912
6033
|
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ jsx26(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ jsx26(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
5913
|
-
item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) :
|
|
6034
|
+
item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
|
|
6035
|
+
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6036
|
+
// which would invite replacing a working two-factor secret.
|
|
6037
|
+
/* @__PURE__ */ jsx26(VaultRow, { label: "One-time password", actions: canTurnOn ? /* @__PURE__ */ jsx26(TurnOnButton, { label: "One-time password", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ jsx26("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
6038
|
+
) : /* @__PURE__ */ jsx26(AddRow, { label: "One-time password", onAdd: canEdit ? () => onMode("edit") : null, children: "Set up" }),
|
|
5914
6039
|
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
5915
6040
|
] }),
|
|
5916
6041
|
/* @__PURE__ */ jsx26(VaultSection, { children: item.notes ? /* @__PURE__ */ jsx26(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ jsx26(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
|
|
@@ -5942,7 +6067,7 @@ function subtitleOf(item, withOwner) {
|
|
|
5942
6067
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
5943
6068
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
5944
6069
|
}
|
|
5945
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header }) {
|
|
6070
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
|
|
5946
6071
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
5947
6072
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
5948
6073
|
const ordered = [...pinned, ...rest];
|
|
@@ -5961,7 +6086,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
5961
6086
|
listRef.current?.querySelector(`[data-item="${next.id}"]`)?.scrollIntoView({ block: "nearest" });
|
|
5962
6087
|
}
|
|
5963
6088
|
};
|
|
5964
|
-
const mixedOwners = new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6089
|
+
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
5965
6090
|
const row = (i) => /* @__PURE__ */ jsx27(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
|
|
5966
6091
|
const sortLabel = SORTS2.find((s) => s.value === sort)?.label ?? "Name";
|
|
5967
6092
|
return /* @__PURE__ */ jsxs25("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
@@ -6114,7 +6239,7 @@ function refusalText(reason) {
|
|
|
6114
6239
|
// src/lists/RestorePanel.tsx
|
|
6115
6240
|
import { useEffect as useEffect18, useState as useState28 } from "react";
|
|
6116
6241
|
import { Button as Button23 } from "@ai-matrx/design-system/controls";
|
|
6117
|
-
import { Fragment as
|
|
6242
|
+
import { Fragment as Fragment17, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6118
6243
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6119
6244
|
function RestorePanel({ lists, item, restore, onClose }) {
|
|
6120
6245
|
const [preview, setPreview] = useState28(null);
|
|
@@ -6159,7 +6284,7 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6159
6284
|
title: `Restore "${item.name}"`,
|
|
6160
6285
|
size: "md",
|
|
6161
6286
|
onClose,
|
|
6162
|
-
footer: /* @__PURE__ */ jsxs26(
|
|
6287
|
+
footer: /* @__PURE__ */ jsxs26(Fragment17, { children: [
|
|
6163
6288
|
/* @__PURE__ */ jsx28(Button23, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
|
|
6164
6289
|
refused ? null : /* @__PURE__ */ jsx28(Button23, { variant: "primary", icon: /* @__PURE__ */ jsx28(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
|
|
6165
6290
|
] }),
|
|
@@ -6179,6 +6304,9 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6179
6304
|
|
|
6180
6305
|
// src/lists/TrashView.tsx
|
|
6181
6306
|
import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
6307
|
+
function trashLineOf(item) {
|
|
6308
|
+
return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
|
|
6309
|
+
}
|
|
6182
6310
|
function TrashView({ port, deleted, query, header, onChanged }) {
|
|
6183
6311
|
const confirmed = useConfirmed();
|
|
6184
6312
|
const [busyId, setBusyId] = useState29(null);
|
|
@@ -6190,7 +6318,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6190
6318
|
setMessage(null);
|
|
6191
6319
|
try {
|
|
6192
6320
|
const r = await confirmed(() => port.lists.restore(item, deletionId));
|
|
6193
|
-
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files.
|
|
6321
|
+
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.` });
|
|
6194
6322
|
onChanged();
|
|
6195
6323
|
return r;
|
|
6196
6324
|
} catch (e) {
|
|
@@ -6208,7 +6336,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6208
6336
|
/* @__PURE__ */ jsxs27("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
|
|
6209
6337
|
/* @__PURE__ */ jsxs27("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6210
6338
|
/* @__PURE__ */ jsx29("span", { className: "truncate text-sm text-foreground", children: item.name }),
|
|
6211
|
-
/* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children:
|
|
6339
|
+
/* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
|
|
6212
6340
|
] }),
|
|
6213
6341
|
/* @__PURE__ */ jsx29(Button24, { variant: "outline", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6214
6342
|
] }, item.id)
|
|
@@ -6499,10 +6627,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6499
6627
|
title: "Send securely",
|
|
6500
6628
|
size: "md",
|
|
6501
6629
|
onClose,
|
|
6502
|
-
footer: /* @__PURE__ */ jsxs29(
|
|
6503
|
-
/* @__PURE__ */ jsx31("div", { className: "w-full sm:w-auto sm:min-w-0 sm:flex-1", children: /* @__PURE__ */ jsx31(StatusLine, { error, notice }) }),
|
|
6630
|
+
footer: /* @__PURE__ */ jsxs29(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx31(StatusLine, { error, notice }) : null, children: [
|
|
6504
6631
|
sameChannelSent && !error ? /* @__PURE__ */ jsx31(Badge8, { tone: "warning", children: "Both by email" }) : null,
|
|
6505
|
-
/* @__PURE__ */ jsx31(Button26, { variant: "quiet",
|
|
6632
|
+
/* @__PURE__ */ jsx31(Button26, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
6506
6633
|
/* @__PURE__ */ jsx31(Button26, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
|
|
6507
6634
|
] }),
|
|
6508
6635
|
children: [
|
|
@@ -6655,7 +6782,7 @@ function addPasskeyFailure(message2) {
|
|
|
6655
6782
|
var isRevoked = (d) => d.revokedAt !== null;
|
|
6656
6783
|
|
|
6657
6784
|
// src/devices/DevicesPanel.tsx
|
|
6658
|
-
import { Fragment as
|
|
6785
|
+
import { Fragment as Fragment18, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6659
6786
|
var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
6660
6787
|
function ErrorLine2({ text }) {
|
|
6661
6788
|
return text ? /* @__PURE__ */ jsx32("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
|
|
@@ -6786,7 +6913,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6786
6913
|
};
|
|
6787
6914
|
const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
|
|
6788
6915
|
const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
|
|
6789
|
-
const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(
|
|
6916
|
+
const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
|
|
6790
6917
|
/* @__PURE__ */ jsx32(Button27, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
|
|
6791
6918
|
canApprove ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", icon: /* @__PURE__ */ jsx32(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
|
|
6792
6919
|
] });
|
|
@@ -6794,7 +6921,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6794
6921
|
"This link names no key. Start again from ",
|
|
6795
6922
|
where,
|
|
6796
6923
|
"."
|
|
6797
|
-
] }) }) : /* @__PURE__ */ jsxs30(
|
|
6924
|
+
] }) }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
|
|
6798
6925
|
/* @__PURE__ */ jsxs30(VaultSection, { title: "What is asking", children: [
|
|
6799
6926
|
/* @__PURE__ */ jsx32(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
|
|
6800
6927
|
name ? /* @__PURE__ */ jsx32(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx32("span", { className: "block truncate", children: name }) }) : null,
|
|
@@ -7094,7 +7221,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7094
7221
|
}
|
|
7095
7222
|
|
|
7096
7223
|
// src/native/NativeImportPanel.tsx
|
|
7097
|
-
import { Fragment as
|
|
7224
|
+
import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
7098
7225
|
var TONE = {
|
|
7099
7226
|
eligible: "success",
|
|
7100
7227
|
committed: "success",
|
|
@@ -7138,16 +7265,16 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7138
7265
|
const yes = await confirm12({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
|
|
7139
7266
|
if (yes) await flow.confirm();
|
|
7140
7267
|
};
|
|
7141
|
-
const footer = preview ? /* @__PURE__ */ jsxs31(
|
|
7268
|
+
const footer = preview ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7142
7269
|
/* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
|
|
7143
7270
|
/* @__PURE__ */ jsxs31(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
|
|
7144
7271
|
"Import ",
|
|
7145
7272
|
ready
|
|
7146
7273
|
] })
|
|
7147
|
-
] }) : status ? active ? /* @__PURE__ */ jsxs31(
|
|
7274
|
+
] }) : status ? active ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7148
7275
|
/* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
|
|
7149
7276
|
/* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
|
|
7150
|
-
] }) : /* @__PURE__ */ jsxs31(
|
|
7277
|
+
] }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7151
7278
|
/* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: flow.reset, children: "New file" }),
|
|
7152
7279
|
/* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" })
|
|
7153
7280
|
] }) : /* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: onClose, children: "Close" });
|
|
@@ -7186,7 +7313,7 @@ import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
|
7186
7313
|
// src/extension/CaptureCard.tsx
|
|
7187
7314
|
import { useState as useState35, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
7188
7315
|
import { Button as Button29, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
|
|
7189
|
-
import { Fragment as
|
|
7316
|
+
import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7190
7317
|
var SEARCH_FROM = 4;
|
|
7191
7318
|
function CaptureCard({ capture, onChanged }) {
|
|
7192
7319
|
const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
|
|
@@ -7219,7 +7346,7 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7219
7346
|
] }),
|
|
7220
7347
|
/* @__PURE__ */ jsx34(Button29, { variant: "quiet", icon: /* @__PURE__ */ jsx34(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
|
|
7221
7348
|
] }),
|
|
7222
|
-
prompt.unavailable ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs32(
|
|
7349
|
+
prompt.unavailable ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs32(Fragment20, { children: [
|
|
7223
7350
|
existing.length > 0 ? /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1", children: [
|
|
7224
7351
|
existing.length >= SEARCH_FROM ? /* @__PURE__ */ jsx34(SearchField3, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
|
|
7225
7352
|
/* @__PURE__ */ jsxs32("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
|
|
@@ -7325,7 +7452,7 @@ import { useState as useState37 } from "react";
|
|
|
7325
7452
|
import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
|
|
7326
7453
|
import { Button as Button31 } from "@ai-matrx/design-system/controls";
|
|
7327
7454
|
import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
|
|
7328
|
-
import { Fragment as
|
|
7455
|
+
import { Fragment as Fragment21, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
7329
7456
|
var HOLD_MS = 6e4;
|
|
7330
7457
|
function PageGenerator({ fields }) {
|
|
7331
7458
|
const limits = useGeneratorLimitsSource();
|
|
@@ -7376,12 +7503,12 @@ function PageGenerator({ fields }) {
|
|
|
7376
7503
|
}
|
|
7377
7504
|
};
|
|
7378
7505
|
const value = held.value;
|
|
7379
|
-
return /* @__PURE__ */ jsxs34(
|
|
7506
|
+
return /* @__PURE__ */ jsxs34(Fragment21, { children: [
|
|
7380
7507
|
/* @__PURE__ */ jsx36(
|
|
7381
7508
|
VaultRow,
|
|
7382
7509
|
{
|
|
7383
7510
|
label: "New password",
|
|
7384
|
-
actions: /* @__PURE__ */ jsxs34(
|
|
7511
|
+
actions: /* @__PURE__ */ jsxs34(Fragment21, { children: [
|
|
7385
7512
|
value ? /* @__PURE__ */ jsx36(Button31, { variant: "quiet", icon: /* @__PURE__ */ jsx36(CopyIcon7, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
|
|
7386
7513
|
/* @__PURE__ */ jsxs34(Popover2, { open, onOpenChange: setOpen, children: [
|
|
7387
7514
|
/* @__PURE__ */ jsx36(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx36(Button31, { variant: "outline", icon: /* @__PURE__ */ jsx36(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
|
|
@@ -7758,8 +7885,33 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7758
7885
|
},
|
|
7759
7886
|
[loc, move]
|
|
7760
7887
|
);
|
|
7888
|
+
const keyState = useRef19({ loc, go });
|
|
7889
|
+
keyState.current = { loc, go };
|
|
7890
|
+
useEffect23(() => {
|
|
7891
|
+
const onKey = (e) => {
|
|
7892
|
+
if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
7893
|
+
const root = rootRef.current;
|
|
7894
|
+
const at = document.activeElement;
|
|
7895
|
+
if (!root || at && at !== document.body && !root.contains(at)) return;
|
|
7896
|
+
if (at instanceof HTMLElement && (at.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(at.tagName))) return;
|
|
7897
|
+
if (document.querySelector('[role="dialog"], [role="alertdialog"]')) return;
|
|
7898
|
+
const { loc: here, go: to } = keyState.current;
|
|
7899
|
+
if (e.key === "/") {
|
|
7900
|
+
const search = root.querySelector('input[aria-label^="Search"]');
|
|
7901
|
+
if (!search) return;
|
|
7902
|
+
e.preventDefault();
|
|
7903
|
+
search.focus();
|
|
7904
|
+
} else if (e.key === "Escape" && here.itemId && here.mode === "view" && !here.panel) {
|
|
7905
|
+
e.preventDefault();
|
|
7906
|
+
to({ itemId: null, mode: "view", panel: null });
|
|
7907
|
+
}
|
|
7908
|
+
};
|
|
7909
|
+
document.addEventListener("keydown", onKey);
|
|
7910
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
7911
|
+
}, []);
|
|
7761
7912
|
const knobsRef = useRef19(host.knobs);
|
|
7762
7913
|
knobsRef.current = host.knobs;
|
|
7914
|
+
const [signedOut, setSignedOut] = useState40(false);
|
|
7763
7915
|
const load = useCallback5(() => {
|
|
7764
7916
|
setError(null);
|
|
7765
7917
|
port.load().then((s) => {
|
|
@@ -7770,7 +7922,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7770
7922
|
(rows) => setDeleted([...s.deleted, ...rows.filter((r) => !s.deleted.some((d) => d.id === r.id))]),
|
|
7771
7923
|
() => void 0
|
|
7772
7924
|
);
|
|
7773
|
-
}).catch((e) =>
|
|
7925
|
+
}).catch((e) => {
|
|
7926
|
+
setSignedOut(e?.status === 401);
|
|
7927
|
+
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
7928
|
+
});
|
|
7774
7929
|
port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
|
|
7775
7930
|
knobsRef.current?.().catch(() => void 0);
|
|
7776
7931
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
@@ -7784,6 +7939,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7784
7939
|
const orgs = snap?.organizations ?? [];
|
|
7785
7940
|
const definitions = snap?.definitions ?? [];
|
|
7786
7941
|
const inThisVault = useMemo6(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
|
|
7942
|
+
const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
7787
7943
|
const views = useMemo6(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
|
|
7788
7944
|
const visible = useMemo6(() => {
|
|
7789
7945
|
const filtered = inThisVault.filter((i) => {
|
|
@@ -7824,8 +7980,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7824
7980
|
return /* @__PURE__ */ jsxs37("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: [
|
|
7825
7981
|
/* @__PURE__ */ jsx39(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
7826
7982
|
/* @__PURE__ */ jsx39("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
|
|
7827
|
-
/* @__PURE__ */ jsx39("div", { className: "max-w-xs text-muted-foreground", children: plainLoadError(error) }),
|
|
7828
|
-
/* @__PURE__ */
|
|
7983
|
+
/* @__PURE__ */ jsx39("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
|
|
7984
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex gap-2", children: [
|
|
7985
|
+
signedOut && host.signIn ? /* @__PURE__ */ jsx39(Button33, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
|
|
7986
|
+
/* @__PURE__ */ jsx39(Button33, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
|
|
7987
|
+
] })
|
|
7829
7988
|
] });
|
|
7830
7989
|
}
|
|
7831
7990
|
if (!snap) {
|
|
@@ -7905,6 +8064,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7905
8064
|
{
|
|
7906
8065
|
title,
|
|
7907
8066
|
items: visible,
|
|
8067
|
+
showOwner: vaultMixesOwners,
|
|
7908
8068
|
definitions,
|
|
7909
8069
|
port,
|
|
7910
8070
|
selectedId: loc.itemId,
|
|
@@ -8306,6 +8466,7 @@ function createFieldsPort(ctx) {
|
|
|
8306
8466
|
if (patch.uriMatchMode !== void 0) body.uri_match_mode = patch.uriMatchMode;
|
|
8307
8467
|
if (patch.browserFillEnabled !== void 0) body.browser_fill_enabled = patch.browserFillEnabled;
|
|
8308
8468
|
if (patch.loginUrls !== void 0) body.login_urls = patch.loginUrls;
|
|
8469
|
+
if (patch.active !== void 0) body.status = patch.active ? "active" : "disabled";
|
|
8309
8470
|
await account3.updateItem(api, { path: { item_id: item.id }, body }, ctx.optsFor(item));
|
|
8310
8471
|
return reread(item);
|
|
8311
8472
|
},
|
|
@@ -8677,6 +8838,7 @@ async function readNativeImportLimits(api, organizationId) {
|
|
|
8677
8838
|
var recoveryOf = (w) => w.lifecycle?.vault_recovery;
|
|
8678
8839
|
var isDeleted = (w) => recoveryOf(w)?.state === "deleted";
|
|
8679
8840
|
var MATCH_MODES2 = ["host", "domain", "exact", "never"];
|
|
8841
|
+
var FIELD_WORDS = { totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
|
|
8680
8842
|
var handlingOf = (v) => v === "visible" || v === "sealed" ? v : "revealable";
|
|
8681
8843
|
function fieldOf(w, def) {
|
|
8682
8844
|
const declared = def?.fields.find((f) => f.key === w.field_key);
|
|
@@ -8684,7 +8846,7 @@ function fieldOf(w, def) {
|
|
|
8684
8846
|
return {
|
|
8685
8847
|
id: w.id,
|
|
8686
8848
|
key: w.field_key,
|
|
8687
|
-
label: declared?.label ?? humanize(w.field_key),
|
|
8849
|
+
label: declared?.label ?? FIELD_WORDS[w.field_key] ?? humanize(w.field_key),
|
|
8688
8850
|
kind: declared?.kind ?? (handling === "visible" ? "text" : "secret"),
|
|
8689
8851
|
handling,
|
|
8690
8852
|
editable: w.editable ?? true,
|
|
@@ -8717,6 +8879,7 @@ function itemOf(w, owner, defs, auth) {
|
|
|
8717
8879
|
uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
|
|
8718
8880
|
browserFillEnabled: w.browser_fill_enabled ?? true,
|
|
8719
8881
|
accessMode: w.access_mode ?? null,
|
|
8882
|
+
turnedOff: w.status === "disabled",
|
|
8720
8883
|
ownerUserId: w.user_id ?? null,
|
|
8721
8884
|
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,
|
|
8722
8885
|
updatedAt: w.updated_at,
|
|
@@ -8776,9 +8939,12 @@ function createApiVaultPort(api, options = {}) {
|
|
|
8776
8939
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
8777
8940
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
8778
8941
|
const sharedP = retrying(() => account9.sharedWithMe(api));
|
|
8942
|
+
const quiet = (p) => void p.catch(() => void 0);
|
|
8943
|
+
[catalogP, authP, userP, sharedP].forEach(quiet);
|
|
8779
8944
|
const org = options.organizations ? null : await retrying(() => platform.listMyOrganizations(api));
|
|
8780
8945
|
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()];
|
|
8781
8946
|
const orgListsP = orgs.map((o) => retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id })));
|
|
8947
|
+
orgListsP.forEach(quiet);
|
|
8782
8948
|
const [catalog, mine] = await Promise.all([catalogP, userP]);
|
|
8783
8949
|
const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
|
|
8784
8950
|
const unavailable = [];
|
|
@@ -8902,9 +9068,11 @@ function createVaultKnobs(client, address) {
|
|
|
8902
9068
|
}
|
|
8903
9069
|
export {
|
|
8904
9070
|
CATEGORIES,
|
|
9071
|
+
CONFIRM_RETURN_KEY,
|
|
8905
9072
|
DEFAULT_LOCATION,
|
|
8906
9073
|
GenerateButton,
|
|
8907
9074
|
HIDDEN_ITEM_TAG,
|
|
9075
|
+
IdentityGate,
|
|
8908
9076
|
LOCKED_MESSAGE,
|
|
8909
9077
|
VaultApp,
|
|
8910
9078
|
VaultLockedError,
|
|
@@ -8922,6 +9090,9 @@ export {
|
|
|
8922
9090
|
matchesQuery,
|
|
8923
9091
|
needsRecentSignIn,
|
|
8924
9092
|
parseDefinitions,
|
|
8925
|
-
|
|
9093
|
+
siteDomainOf,
|
|
9094
|
+
sortItems,
|
|
9095
|
+
useConfirmed,
|
|
9096
|
+
wasCancelled
|
|
8926
9097
|
};
|
|
8927
9098
|
//# sourceMappingURL=index.js.map
|