@ai-matrx/vault 0.1.10 → 0.1.12
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 +42 -1
- package/dist/index.cjs +215 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -4
- package/dist/index.d.ts +71 -4
- package/dist/index.js +278 -114
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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();
|
|
@@ -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
|
}
|
|
@@ -798,6 +876,8 @@ function matchesQuery(item, query) {
|
|
|
798
876
|
if (!q) return true;
|
|
799
877
|
return [item.name, item.definitionLabel, ...item.tags, ...item.loginUrls, ...item.custom.map((c) => `${c.label} ${c.value}`)].some((h) => h.toLowerCase().includes(q));
|
|
800
878
|
}
|
|
879
|
+
var HIDDEN_ITEM_TAG = "matrx:hidden";
|
|
880
|
+
var isHiddenItem = (item) => (item.tags ?? []).includes(HIDDEN_ITEM_TAG);
|
|
801
881
|
var isAuthenticatorStorage = (key) => key === "totp_seed" || key.startsWith("totp_") || key === "authenticator_last_time_step";
|
|
802
882
|
function loginSiteOf(item) {
|
|
803
883
|
const raw = item.loginUrls[0];
|
|
@@ -808,14 +888,27 @@ function loginSiteOf(item) {
|
|
|
808
888
|
return raw.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? "";
|
|
809
889
|
}
|
|
810
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
|
+
}
|
|
811
902
|
function sortItems(items, sort) {
|
|
812
903
|
const out = [...items];
|
|
813
904
|
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
814
905
|
if (sort === "name") return out.sort(byName);
|
|
815
|
-
if (sort === "website")
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
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
|
+
});
|
|
819
912
|
if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
820
913
|
return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
821
914
|
}
|
|
@@ -1206,7 +1299,7 @@ import { useEffect as useEffect6, useRef as useRef4, useState as useState6 } fro
|
|
|
1206
1299
|
import { Button as Button3 } from "@ai-matrx/design-system/controls";
|
|
1207
1300
|
import { cn as cn4 } from "@ai-matrx/design-system";
|
|
1208
1301
|
import { formatAbsoluteDate } from "@ai-matrx/kit/format";
|
|
1209
|
-
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";
|
|
1210
1303
|
var PAGE = 50;
|
|
1211
1304
|
var MAX = 500;
|
|
1212
1305
|
function ActivityPanel({ item, port, onClose }) {
|
|
@@ -1235,7 +1328,10 @@ function ActivityPanel({ item, port, onClose }) {
|
|
|
1235
1328
|
{
|
|
1236
1329
|
title: "Activity",
|
|
1237
1330
|
onClose,
|
|
1238
|
-
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
|
+
] }),
|
|
1239
1335
|
children: [
|
|
1240
1336
|
error ? /* @__PURE__ */ jsx6("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
|
|
1241
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(
|
|
@@ -1258,7 +1354,7 @@ function ActivityPanel({ item, port, onClose }) {
|
|
|
1258
1354
|
}
|
|
1259
1355
|
|
|
1260
1356
|
// src/activity/HistoryPanel.tsx
|
|
1261
|
-
import { Fragment as
|
|
1357
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1262
1358
|
var MASK2 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
1263
1359
|
var messageOf = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
1264
1360
|
function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
@@ -1318,8 +1414,11 @@ function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
|
1318
1414
|
{
|
|
1319
1415
|
title: "Password history",
|
|
1320
1416
|
onClose,
|
|
1321
|
-
footer:
|
|
1322
|
-
|
|
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: [
|
|
1323
1422
|
error ? /* @__PURE__ */ jsx7("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
|
|
1324
1423
|
notice ? /* @__PURE__ */ jsx7("p", { role: "status", className: "px-1 text-sm text-success", children: notice }) : null,
|
|
1325
1424
|
page && groups.length === 0 ? /* @__PURE__ */ jsx7(Empty, { children: "No earlier values yet." }) : null,
|
|
@@ -1387,7 +1486,7 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
|
|
|
1387
1486
|
VaultRow,
|
|
1388
1487
|
{
|
|
1389
1488
|
label: when,
|
|
1390
|
-
actions: entry.available ? /* @__PURE__ */ jsxs7(
|
|
1489
|
+
actions: entry.available ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1391
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() }),
|
|
1392
1491
|
/* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: /* @__PURE__ */ jsx7(CopyIcon2, {}), "aria-label": "Copy", disabled: busy, onClick: () => void copy() }),
|
|
1393
1492
|
canRestore(page, entry) ? /* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: /* @__PURE__ */ jsx7(RestoreGlyph, {}), "aria-label": "Restore", disabled: busy, onClick: () => void restore() }) : null
|
|
@@ -1721,7 +1820,7 @@ function imageFrom(data) {
|
|
|
1721
1820
|
}
|
|
1722
1821
|
|
|
1723
1822
|
// src/authenticator/Setup.tsx
|
|
1724
|
-
import { Fragment as
|
|
1823
|
+
import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1725
1824
|
function useCanScan() {
|
|
1726
1825
|
const [ok, setOk] = useState10(false);
|
|
1727
1826
|
useEffect10(() => {
|
|
@@ -1854,7 +1953,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1854
1953
|
VaultRow,
|
|
1855
1954
|
{
|
|
1856
1955
|
label,
|
|
1857
|
-
actions: /* @__PURE__ */ jsxs9(
|
|
1956
|
+
actions: /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1858
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() }),
|
|
1859
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
|
|
1860
1959
|
] }),
|
|
@@ -1923,13 +2022,14 @@ import { confirm as confirm2 } from "@ai-matrx/kit/confirm-opener";
|
|
|
1923
2022
|
|
|
1924
2023
|
// src/authenticator/port.ts
|
|
1925
2024
|
var MFA_METHOD_KEY = "mfa_method";
|
|
2025
|
+
var OTP_SEED_KEY = "totp_seed";
|
|
1926
2026
|
function mfaMethodOf(item) {
|
|
1927
2027
|
const v = item.custom.find((c) => c.key === MFA_METHOD_KEY)?.value;
|
|
1928
2028
|
return v === "sms" ? "sms" : v ? "push_or_other" : null;
|
|
1929
2029
|
}
|
|
1930
2030
|
|
|
1931
2031
|
// src/authenticator/TotpRows.tsx
|
|
1932
|
-
import { Fragment as
|
|
2032
|
+
import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1933
2033
|
function otpActionError(e, what) {
|
|
1934
2034
|
const status = e?.status;
|
|
1935
2035
|
if (status === 404) return "There is no one-time password here.";
|
|
@@ -2004,7 +2104,7 @@ function TotpRow({ port, item, onChanged }) {
|
|
|
2004
2104
|
VaultRow,
|
|
2005
2105
|
{
|
|
2006
2106
|
label: "One-time password",
|
|
2007
|
-
actions: /* @__PURE__ */ jsxs10(
|
|
2107
|
+
actions: /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
2008
2108
|
a.enabled ? /* @__PURE__ */ jsx10(CopyCodeButton, { live, label: item.name }) : null,
|
|
2009
2109
|
menu
|
|
2010
2110
|
] }),
|
|
@@ -2087,7 +2187,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
|
|
|
2087
2187
|
}
|
|
2088
2188
|
|
|
2089
2189
|
// src/authenticator/AddOtpPanel.tsx
|
|
2090
|
-
import { Fragment as
|
|
2190
|
+
import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2091
2191
|
var NEW = "__new__";
|
|
2092
2192
|
var LOGIN_KEYS = ["website_login", "username_password"];
|
|
2093
2193
|
function normalizeWebsite(raw) {
|
|
@@ -2170,7 +2270,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2170
2270
|
title: "Add one-time password",
|
|
2171
2271
|
size: "md",
|
|
2172
2272
|
onClose,
|
|
2173
|
-
footer: /* @__PURE__ */ jsxs11(
|
|
2273
|
+
footer: /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2174
2274
|
/* @__PURE__ */ jsx11(Button8, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2175
2275
|
/* @__PURE__ */ jsx11(Button8, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
|
|
2176
2276
|
] }),
|
|
@@ -2210,7 +2310,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2210
2310
|
}
|
|
2211
2311
|
}
|
|
2212
2312
|
) }),
|
|
2213
|
-
isNew ? /* @__PURE__ */ jsxs11(
|
|
2313
|
+
isNew ? /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2214
2314
|
/* @__PURE__ */ jsx11(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx11(
|
|
2215
2315
|
Field4,
|
|
2216
2316
|
{
|
|
@@ -2242,7 +2342,7 @@ function AddedPanel({ port, item, onClose, onDone }) {
|
|
|
2242
2342
|
}
|
|
2243
2343
|
|
|
2244
2344
|
// src/authenticator/AuthenticatorView.tsx
|
|
2245
|
-
import { Fragment as
|
|
2345
|
+
import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2246
2346
|
function matchesEntry(entry, q) {
|
|
2247
2347
|
if (!entry || !q) return false;
|
|
2248
2348
|
return [entry.issuer, entry.account].some((v) => v?.toLowerCase().includes(q));
|
|
@@ -2281,7 +2381,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2281
2381
|
const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
|
|
2282
2382
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
2283
2383
|
return /* @__PURE__ */ jsxs12("section", { "aria-label": "One-time passwords", className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
2284
|
-
header,
|
|
2384
|
+
header ? /* @__PURE__ */ jsx12("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
|
|
2285
2385
|
/* @__PURE__ */ jsxs12("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
|
|
2286
2386
|
/* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-baseline gap-2", children: [
|
|
2287
2387
|
/* @__PURE__ */ jsx12("h2", { className: "truncate text-sm font-semibold text-foreground", children: "One-time passwords" }),
|
|
@@ -2293,7 +2393,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2293
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" }) }),
|
|
2294
2394
|
/* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-foreground", children: "No one-time passwords yet" }),
|
|
2295
2395
|
/* @__PURE__ */ jsx12(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx12(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add one-time password" })
|
|
2296
|
-
] }) : 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(
|
|
2297
2397
|
OtpListRow,
|
|
2298
2398
|
{
|
|
2299
2399
|
port,
|
|
@@ -2390,7 +2490,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, on
|
|
|
2390
2490
|
/* @__PURE__ */ jsx12(CopyIcon4, { className: "size-4" }),
|
|
2391
2491
|
"Copy code"
|
|
2392
2492
|
] }) : null,
|
|
2393
|
-
canManage ? /* @__PURE__ */ jsxs12(
|
|
2493
|
+
canManage ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
|
|
2394
2494
|
/* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onRename, children: [
|
|
2395
2495
|
/* @__PURE__ */ jsx12(PencilGlyph, { className: "size-4" }),
|
|
2396
2496
|
"Rename"
|
|
@@ -2430,9 +2530,9 @@ function sandboxBlocker(envKeyDraft, savedEnvKey) {
|
|
|
2430
2530
|
return null;
|
|
2431
2531
|
}
|
|
2432
2532
|
var HANDLING_WORDS = {
|
|
2433
|
-
visible: { label: "
|
|
2434
|
-
revealable: { label: "
|
|
2435
|
-
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." }
|
|
2436
2536
|
};
|
|
2437
2537
|
function handlingChoices(current) {
|
|
2438
2538
|
return current === "sealed" ? ["sealed"] : ["visible", "revealable", "sealed"];
|
|
@@ -2614,7 +2714,7 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2614
2714
|
}
|
|
2615
2715
|
) }),
|
|
2616
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 }) }) }),
|
|
2617
|
-
/* @__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 }) }) })
|
|
2618
2718
|
] }),
|
|
2619
2719
|
error ? /* @__PURE__ */ jsx13(Problem, { children: error }) : null
|
|
2620
2720
|
] });
|
|
@@ -2682,7 +2782,7 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2682
2782
|
f.envKey
|
|
2683
2783
|
] }) : null,
|
|
2684
2784
|
f.injectIntoSandbox ? /* @__PURE__ */ jsx13("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
|
|
2685
|
-
!f.active ? /* @__PURE__ */ jsx13("span", { className: "text-
|
|
2785
|
+
!f.active ? /* @__PURE__ */ jsx13("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
|
|
2686
2786
|
] })
|
|
2687
2787
|
},
|
|
2688
2788
|
f.id
|
|
@@ -3078,7 +3178,7 @@ function startNewRestoreRun(preview) {
|
|
|
3078
3178
|
import { useState as useState16 } from "react";
|
|
3079
3179
|
import { Checkbox } from "@ai-matrx/design-system";
|
|
3080
3180
|
import { Badge as Badge4, Button as Button12, DisclosureHeader as DisclosureHeader2 } from "@ai-matrx/design-system/controls";
|
|
3081
|
-
import { Fragment as
|
|
3181
|
+
import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3082
3182
|
function PickLine({ checked, onChange, disabled = false, title, detail, badge, tone }) {
|
|
3083
3183
|
return /* @__PURE__ */ jsxs15("label", { className: "flex min-h-11 items-center gap-3 px-4 py-1", "data-clickable": disabled ? void 0 : "", children: [
|
|
3084
3184
|
/* @__PURE__ */ jsx15(Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
|
|
@@ -3090,7 +3190,7 @@ function PickLine({ checked, onChange, disabled = false, title, detail, badge, t
|
|
|
3090
3190
|
function Windowed({ items, size = 150, render }) {
|
|
3091
3191
|
const [all, setAll] = useState16(false);
|
|
3092
3192
|
const shown = all ? items : items.slice(0, size);
|
|
3093
|
-
return /* @__PURE__ */ jsxs15(
|
|
3193
|
+
return /* @__PURE__ */ jsxs15(Fragment9, { children: [
|
|
3094
3194
|
shown.map(render),
|
|
3095
3195
|
items.length > shown.length ? /* @__PURE__ */ jsx15("div", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs15(Button12, { variant: "quiet", onClick: () => setAll(true), children: [
|
|
3096
3196
|
"Show all ",
|
|
@@ -3111,7 +3211,7 @@ function ErrorLine({ message: message2 }) {
|
|
|
3111
3211
|
var plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
3112
3212
|
|
|
3113
3213
|
// src/io/BackupPanel.tsx
|
|
3114
|
-
import { Fragment as
|
|
3214
|
+
import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3115
3215
|
var RECORD_STATUS = {
|
|
3116
3216
|
created: "Restored",
|
|
3117
3217
|
replayed: "Already restored",
|
|
@@ -3239,13 +3339,13 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3239
3339
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3240
3340
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3241
3341
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3242
|
-
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(
|
|
3342
|
+
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3243
3343
|
/* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3244
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: [
|
|
3245
3345
|
"Review ",
|
|
3246
3346
|
selected.size
|
|
3247
3347
|
] })
|
|
3248
|
-
] }) : /* @__PURE__ */ jsxs16(
|
|
3348
|
+
] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3249
3349
|
/* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
|
|
3250
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: [
|
|
3251
3351
|
"Restore ",
|
|
@@ -3266,12 +3366,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3266
3366
|
]
|
|
3267
3367
|
}
|
|
3268
3368
|
),
|
|
3269
|
-
mode === "backup" ? /* @__PURE__ */ jsxs16(
|
|
3369
|
+
mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3270
3370
|
/* @__PURE__ */ jsx16(
|
|
3271
3371
|
VaultSection,
|
|
3272
3372
|
{
|
|
3273
3373
|
title: `${selected.size} of ${plural(items.length, "credential")}`,
|
|
3274
|
-
actions: /* @__PURE__ */ jsxs16(
|
|
3374
|
+
actions: /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3275
3375
|
/* @__PURE__ */ jsx16(Button13, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
|
|
3276
3376
|
setBackup(null);
|
|
3277
3377
|
setSelected(new Set(items.map((i) => i.id)));
|
|
@@ -3284,7 +3384,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3284
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) })
|
|
3285
3385
|
}
|
|
3286
3386
|
),
|
|
3287
|
-
backup ? /* @__PURE__ */ jsxs16(
|
|
3387
|
+
backup ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3288
3388
|
/* @__PURE__ */ jsx16(Summary, { value: backup }),
|
|
3289
3389
|
/* @__PURE__ */ jsx16(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3290
3390
|
/* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
@@ -3292,7 +3392,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3292
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) }) })
|
|
3293
3393
|
] })
|
|
3294
3394
|
] }) : null
|
|
3295
|
-
] }) : /* @__PURE__ */ jsx16(
|
|
3395
|
+
] }) : /* @__PURE__ */ jsx16(Fragment10, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3296
3396
|
/* @__PURE__ */ jsxs16(VaultRow, { label: "File", ...file ? { hint: file.name } : {}, children: [
|
|
3297
3397
|
/* @__PURE__ */ jsx16(Button13, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
|
|
3298
3398
|
/* @__PURE__ */ jsx16(
|
|
@@ -3310,7 +3410,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3310
3410
|
)
|
|
3311
3411
|
] }),
|
|
3312
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) }) })
|
|
3313
|
-
] }) : /* @__PURE__ */ jsxs16(
|
|
3413
|
+
] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3314
3414
|
/* @__PURE__ */ jsx16(Summary, { value: restorePreview }),
|
|
3315
3415
|
!result ? /* @__PURE__ */ jsx16(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
|
|
3316
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: [
|
|
@@ -3327,7 +3427,7 @@ import { useMemo, useState as useState18 } from "react";
|
|
|
3327
3427
|
import { Button as Button14, Select as Select5 } from "@ai-matrx/design-system/controls";
|
|
3328
3428
|
import { downloadFile as downloadFile2 } from "@ai-matrx/kit/download";
|
|
3329
3429
|
import { confirm as confirm5 } from "@ai-matrx/kit/confirm-opener";
|
|
3330
|
-
import { Fragment as
|
|
3430
|
+
import { Fragment as Fragment11, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3331
3431
|
var FORMATS = [
|
|
3332
3432
|
{ value: "matrx_login_csv_v1", label: "Matrx", hint: "Website logins, all common fields" },
|
|
3333
3433
|
{ value: "firefox_csv_v1", label: "Firefox", hint: "Address, username and password" },
|
|
@@ -3407,7 +3507,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3407
3507
|
title: "Export logins",
|
|
3408
3508
|
size: "lg",
|
|
3409
3509
|
onClose,
|
|
3410
|
-
footer: /* @__PURE__ */ jsxs17(
|
|
3510
|
+
footer: /* @__PURE__ */ jsxs17(Fragment11, { children: [
|
|
3411
3511
|
/* @__PURE__ */ jsx17(Button14, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3412
3512
|
preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */ jsx17(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
|
|
3413
3513
|
"Download ",
|
|
@@ -3434,7 +3534,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3434
3534
|
VaultSection,
|
|
3435
3535
|
{
|
|
3436
3536
|
title: `${selected.size} of ${plural(logins.length, "login")}`,
|
|
3437
|
-
actions: /* @__PURE__ */ jsxs17(
|
|
3537
|
+
actions: /* @__PURE__ */ jsxs17(Fragment11, { children: [
|
|
3438
3538
|
/* @__PURE__ */ jsx17(Button14, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
|
|
3439
3539
|
changed();
|
|
3440
3540
|
setSelected(new Set(logins.map((l) => l.id)));
|
|
@@ -4316,7 +4416,7 @@ async function parseImportFile(source, file, limits, signal) {
|
|
|
4316
4416
|
}
|
|
4317
4417
|
|
|
4318
4418
|
// src/io/ImportPanel.tsx
|
|
4319
|
-
import { Fragment as
|
|
4419
|
+
import { Fragment as Fragment12, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4320
4420
|
var ROLE_OPTIONS = [
|
|
4321
4421
|
{ value: "keep", label: "Keep encrypted" },
|
|
4322
4422
|
{ value: "title", label: "Name" },
|
|
@@ -4491,13 +4591,13 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4491
4591
|
const help = EXPORT_HELP[source];
|
|
4492
4592
|
const stage = done ? "done" : draft ? "review" : "choose";
|
|
4493
4593
|
const busy = running !== null || reading;
|
|
4494
|
-
const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(
|
|
4594
|
+
const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4495
4595
|
/* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
4496
4596
|
source === "env" ? /* @__PURE__ */ jsx18(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx18(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
|
|
4497
|
-
] }) : stage === "review" ? /* @__PURE__ */ jsxs18(
|
|
4597
|
+
] }) : stage === "review" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4498
4598
|
running ? /* @__PURE__ */ jsx18(Button15, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: reset, children: "Back" }),
|
|
4499
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}` })
|
|
4500
|
-
] }) : /* @__PURE__ */ jsxs18(
|
|
4600
|
+
] }) : /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4501
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,
|
|
4502
4602
|
/* @__PURE__ */ jsx18(Button15, { variant: "primary", onClick: onClose, children: "Done" })
|
|
4503
4603
|
] });
|
|
@@ -4527,13 +4627,13 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4527
4627
|
] }),
|
|
4528
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
|
|
4529
4629
|
] }) : null,
|
|
4530
|
-
stage === "review" && draft ? /* @__PURE__ */ jsxs18(
|
|
4630
|
+
stage === "review" && draft ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4531
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,
|
|
4532
4632
|
/* @__PURE__ */ jsx18(
|
|
4533
4633
|
VaultSection,
|
|
4534
4634
|
{
|
|
4535
4635
|
title: draft.kind === "env" ? plural(envKeys.length, "value") : summary(counts, lines.length),
|
|
4536
|
-
actions: /* @__PURE__ */ jsxs18(
|
|
4636
|
+
actions: /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4537
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" }),
|
|
4538
4638
|
/* @__PURE__ */ jsx18(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
|
|
4539
4639
|
] }),
|
|
@@ -4627,7 +4727,7 @@ import { jsx as jsx19 } from "react/jsx-runtime";
|
|
|
4627
4727
|
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
4628
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";
|
|
4629
4729
|
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
4630
|
-
const initial = site
|
|
4730
|
+
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
4631
4731
|
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
4632
4732
|
return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
4633
4733
|
}
|
|
@@ -4650,13 +4750,13 @@ import { cn as cn9 } from "@ai-matrx/design-system";
|
|
|
4650
4750
|
import { confirm as confirm6 } from "@ai-matrx/kit/confirm-opener";
|
|
4651
4751
|
import { downloadFile as downloadFile3 } from "@ai-matrx/kit/download";
|
|
4652
4752
|
import { DownloadIcon } from "@ai-matrx/design-system/icons";
|
|
4653
|
-
import { Fragment as
|
|
4753
|
+
import { Fragment as Fragment13, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4654
4754
|
var messageOf2 = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
4655
4755
|
var TOO_BIG = "Files over 25 MB can't be stored.";
|
|
4656
4756
|
var PROTECTION = [
|
|
4657
4757
|
{ value: "visible", label: "Open", title: "Anyone who can use the item can download it" },
|
|
4658
4758
|
{ value: "revealable", label: "Protected", title: "Downloading needs a recent sign-in" },
|
|
4659
|
-
{ value: "sealed", label: "
|
|
4759
|
+
{ value: "sealed", label: "Never shown", title: "Only automation can use it, never a person" }
|
|
4660
4760
|
];
|
|
4661
4761
|
function FilesSection({ item, port, editing, onChanged }) {
|
|
4662
4762
|
const confirmed = useConfirmed();
|
|
@@ -4723,7 +4823,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4723
4823
|
{
|
|
4724
4824
|
label: a.label,
|
|
4725
4825
|
hint: a.description || void 0,
|
|
4726
|
-
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,
|
|
4727
4827
|
children: /* @__PURE__ */ jsx20(FileName, { file: a })
|
|
4728
4828
|
},
|
|
4729
4829
|
a.id
|
|
@@ -4747,13 +4847,13 @@ function EditableFile({ port, item: it, file: a, busy: b, run: go, onDownload, o
|
|
|
4747
4847
|
const yes = await confirm6({ title: `Delete ${a.label}?`, description: "The encrypted file is removed from this item.", confirmLabel: "Delete", variant: "destructive" });
|
|
4748
4848
|
if (yes) await go(`delete:${a.id}`, () => port.activity.deleteFile(it, a.id), "The file could not be deleted.");
|
|
4749
4849
|
}
|
|
4750
|
-
return /* @__PURE__ */ jsxs19(
|
|
4850
|
+
return /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4751
4851
|
/* @__PURE__ */ jsx20(
|
|
4752
4852
|
VaultRow,
|
|
4753
4853
|
{
|
|
4754
4854
|
label: a.label,
|
|
4755
4855
|
hint: a.description || void 0,
|
|
4756
|
-
actions: /* @__PURE__ */ jsxs19(
|
|
4856
|
+
actions: /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4757
4857
|
canDownload(it, a) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: b !== null, onClick: onDownload }) : null,
|
|
4758
4858
|
/* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PencilGlyph, {}), "aria-label": `Edit ${a.label}`, pressed: open, disabled: b !== null, onClick: () => setOpen((o) => !o) }),
|
|
4759
4859
|
/* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(UploadGlyph, {}), "aria-label": `Replace ${a.fileName}`, disabled: b !== null, onClick: () => replacer.current?.click() }),
|
|
@@ -4807,7 +4907,7 @@ function NewFile({ file, busy, onAdd, onCancel }) {
|
|
|
4807
4907
|
if (handling === "sealed" && !await confirmSeal(label)) return;
|
|
4808
4908
|
await onAdd({ label: label.trim(), description: description.trim() || null, handling });
|
|
4809
4909
|
}
|
|
4810
|
-
return /* @__PURE__ */ jsxs19(
|
|
4910
|
+
return /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4811
4911
|
/* @__PURE__ */ jsx20(VaultRow, { label: "New file", children: /* @__PURE__ */ jsxs19("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
4812
4912
|
/* @__PURE__ */ jsx20("span", { className: "truncate", children: file.name }),
|
|
4813
4913
|
/* @__PURE__ */ jsx20("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize2(file.size) })
|
|
@@ -4831,7 +4931,7 @@ function FileDetailsRows({ file, busy, onSave, onCancel }) {
|
|
|
4831
4931
|
if (handling === "sealed" && file.handling !== "sealed" && !await confirmSeal(label)) return;
|
|
4832
4932
|
await onSave({ label: label.trim(), description: description.trim() || null, fileName: fileName.trim(), handling });
|
|
4833
4933
|
}
|
|
4834
|
-
return /* @__PURE__ */ jsxs19(
|
|
4934
|
+
return /* @__PURE__ */ jsxs19(Fragment13, { children: [
|
|
4835
4935
|
/* @__PURE__ */ jsx20(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "Name", value: label, onChange: (e) => setLabel(e.target.value) }) }),
|
|
4836
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) }) }),
|
|
4837
4937
|
/* @__PURE__ */ jsx20(VaultRow, { label: "File name", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "File name", value: fileName, onChange: (e) => setFileName(e.target.value) }) }),
|
|
@@ -4855,7 +4955,7 @@ function confirmSeal(label) {
|
|
|
4855
4955
|
import { useState as useState21 } from "react";
|
|
4856
4956
|
import { Badge as Badge6, Button as Button17, Textarea as Textarea3 } from "@ai-matrx/design-system/controls";
|
|
4857
4957
|
import { CopyIcon as CopyIcon6 } from "@ai-matrx/design-system/icons";
|
|
4858
|
-
import { Fragment as
|
|
4958
|
+
import { Fragment as Fragment14, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4859
4959
|
var MASK4 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
4860
4960
|
var say2 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
4861
4961
|
function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
@@ -4899,7 +4999,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
4899
4999
|
{
|
|
4900
5000
|
label: "Recovery codes",
|
|
4901
5001
|
top: true,
|
|
4902
|
-
actions: /* @__PURE__ */ jsxs20(
|
|
5002
|
+
actions: /* @__PURE__ */ jsxs20(Fragment14, { children: [
|
|
4903
5003
|
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CheckGlyph, {}), "aria-label": "Save codes", disabled: busy || !draft.trim(), onClick: () => void saveDraft() }),
|
|
4904
5004
|
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx21(XGlyph, {}), "aria-label": "Cancel", disabled: busy, onClick: () => {
|
|
4905
5005
|
setDraft(null);
|
|
@@ -4941,11 +5041,11 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
4941
5041
|
{
|
|
4942
5042
|
label: "Recovery codes",
|
|
4943
5043
|
top: codes !== null,
|
|
4944
|
-
actions: /* @__PURE__ */ jsxs20(
|
|
5044
|
+
actions: /* @__PURE__ */ jsxs20(Fragment14, { children: [
|
|
4945
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,
|
|
4946
5046
|
canEdit && !sealed ? /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(PencilGlyph, {}), "aria-label": "Replace all codes", disabled: busy, onClick: () => setDraft("") }) : null
|
|
4947
5047
|
] }),
|
|
4948
|
-
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: [
|
|
4949
5049
|
codes.map((code, i) => /* @__PURE__ */ jsxs20("li", { className: "flex min-h-7 items-center gap-1", children: [
|
|
4950
5050
|
/* @__PURE__ */ jsx21("code", { className: "min-w-0 flex-1 break-all font-mono text-sm text-foreground", children: code }),
|
|
4951
5051
|
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CopyIcon6, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue2(code, "Recovery code") }),
|
|
@@ -5268,10 +5368,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5268
5368
|
title: "Move or copy",
|
|
5269
5369
|
size: "md",
|
|
5270
5370
|
onClose,
|
|
5271
|
-
footer: /* @__PURE__ */
|
|
5272
|
-
/* @__PURE__ */ jsx24(StatusLine, { error, notice }),
|
|
5273
|
-
/* @__PURE__ */ jsx24(Button19, { variant: "outline", className: "ml-auto", onClick: onClose, children: "Close" })
|
|
5274
|
-
] }),
|
|
5371
|
+
footer: /* @__PURE__ */ jsx24(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx24(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx24(Button19, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5275
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: [
|
|
5276
5373
|
canMove && moves.length > 0 ? /* @__PURE__ */ jsx24(
|
|
5277
5374
|
VaultRow,
|
|
@@ -5303,7 +5400,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5303
5400
|
}
|
|
5304
5401
|
|
|
5305
5402
|
// src/sharing/SharePanel.tsx
|
|
5306
|
-
import { Fragment as
|
|
5403
|
+
import { Fragment as Fragment15, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
5307
5404
|
function useGrants(port, item) {
|
|
5308
5405
|
const [grants, setGrants] = useState25(null);
|
|
5309
5406
|
const [loadError, setLoadError] = useState25(null);
|
|
@@ -5386,10 +5483,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5386
5483
|
title: "Share",
|
|
5387
5484
|
size: "md",
|
|
5388
5485
|
onClose,
|
|
5389
|
-
footer: /* @__PURE__ */
|
|
5390
|
-
/* @__PURE__ */ jsx25(StatusLine, { error, notice }),
|
|
5391
|
-
/* @__PURE__ */ jsx25(Button20, { variant: "primary", className: "ml-auto", onClick: onClose, children: "Done" })
|
|
5392
|
-
] }),
|
|
5486
|
+
footer: /* @__PURE__ */ jsx25(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx25(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5393
5487
|
children: [
|
|
5394
5488
|
/* @__PURE__ */ jsxs23(VaultSection, { title: "Who has access", children: [
|
|
5395
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" }) }),
|
|
@@ -5454,7 +5548,7 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
|
5454
5548
|
const [level, setLevel] = useState25("use");
|
|
5455
5549
|
const chosen = open.find((o) => o.id === target);
|
|
5456
5550
|
if (item.owner.kind !== "me") return null;
|
|
5457
|
-
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: [
|
|
5458
5552
|
/* @__PURE__ */ jsxs23("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5459
5553
|
/* @__PURE__ */ jsx25(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5460
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 }))] }),
|
|
@@ -5540,7 +5634,7 @@ function SharingSummary({ item, port, className }) {
|
|
|
5540
5634
|
|
|
5541
5635
|
// src/ItemPane.tsx
|
|
5542
5636
|
import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
|
|
5543
|
-
import { Fragment as
|
|
5637
|
+
import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5544
5638
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5545
5639
|
function ItemPane(props) {
|
|
5546
5640
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
@@ -5675,6 +5769,21 @@ function ItemPane(props) {
|
|
|
5675
5769
|
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "The value could not be read.");
|
|
5676
5770
|
}
|
|
5677
5771
|
}
|
|
5772
|
+
const offFields = item ? item.fields.filter((f) => !f.active) : [];
|
|
5773
|
+
const seedField = item?.fields.find((f) => f.key === OTP_SEED_KEY) ?? null;
|
|
5774
|
+
const canTurnOn = Boolean(item && canEdit);
|
|
5775
|
+
async function turnOn(fields) {
|
|
5776
|
+
if (!item || fields.length === 0) return;
|
|
5777
|
+
setError(null);
|
|
5778
|
+
try {
|
|
5779
|
+
for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
|
|
5780
|
+
onChanged();
|
|
5781
|
+
} catch (e) {
|
|
5782
|
+
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
|
|
5783
|
+
onChanged();
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5786
|
+
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
5678
5787
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
5679
5788
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
5680
5789
|
const metaValue = (key) => draft.values[key] ?? item?.custom.find((c) => c.key === key)?.value ?? "";
|
|
@@ -5683,6 +5792,10 @@ function ItemPane(props) {
|
|
|
5683
5792
|
const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
|
|
5684
5793
|
const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
|
|
5685
5794
|
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;
|
|
5795
|
+
const sameNamed = (id) => {
|
|
5796
|
+
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
5797
|
+
return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
|
|
5798
|
+
};
|
|
5686
5799
|
const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
|
|
5687
5800
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5688
5801
|
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: [
|
|
@@ -5750,7 +5863,7 @@ function ItemPane(props) {
|
|
|
5750
5863
|
/* @__PURE__ */ jsx26(SettingsIcon, { className: "size-4" }),
|
|
5751
5864
|
"Settings"
|
|
5752
5865
|
] }) : null,
|
|
5753
|
-
canManage ? /* @__PURE__ */ jsxs24(
|
|
5866
|
+
canManage ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5754
5867
|
/* @__PURE__ */ jsx26(DropdownMenuSeparator3, {}),
|
|
5755
5868
|
/* @__PURE__ */ jsxs24(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
|
|
5756
5869
|
/* @__PURE__ */ jsx26(TrashGlyph, { className: "size-4" }),
|
|
@@ -5766,7 +5879,11 @@ function ItemPane(props) {
|
|
|
5766
5879
|
header,
|
|
5767
5880
|
error ? /* @__PURE__ */ jsx26("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
|
|
5768
5881
|
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,
|
|
5769
|
-
|
|
5882
|
+
item && !editing && 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: [
|
|
5883
|
+
/* @__PURE__ */ jsx26("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
|
|
5884
|
+
canTurnOn ? /* @__PURE__ */ jsx26(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
5885
|
+
] }) : null,
|
|
5886
|
+
/* @__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: [
|
|
5770
5887
|
/* @__PURE__ */ jsxs24(VaultSection, { children: [
|
|
5771
5888
|
mode === "new" ? /* @__PURE__ */ jsx26(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx26(
|
|
5772
5889
|
OptionCombobox,
|
|
@@ -5778,16 +5895,16 @@ function ItemPane(props) {
|
|
|
5778
5895
|
searchPlaceholder: "Find an organization",
|
|
5779
5896
|
groups: [
|
|
5780
5897
|
{ heading: "Just you", options: ["me"] },
|
|
5781
|
-
...organizations.length > 0 ? [{ heading: "Organizations", options: organizations.map((o) => o.id) }] : [],
|
|
5898
|
+
...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) }] : [],
|
|
5782
5899
|
{ heading: "Send", options: ["person"] }
|
|
5783
5900
|
],
|
|
5784
5901
|
getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
|
|
5785
|
-
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : null,
|
|
5902
|
+
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
|
|
5786
5903
|
renderIcon: (v) => v === "me" ? /* @__PURE__ */ jsx26(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ jsx26(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ jsx26(BuildingGlyph, { className: "size-4" })
|
|
5787
5904
|
}
|
|
5788
5905
|
) }) : null,
|
|
5789
5906
|
/* @__PURE__ */ jsx26(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
|
|
5790
|
-
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(
|
|
5907
|
+
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5791
5908
|
/* @__PURE__ */ jsx26(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
|
|
5792
5909
|
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
|
|
5793
5910
|
] }) : null,
|
|
@@ -5806,7 +5923,7 @@ function ItemPane(props) {
|
|
|
5806
5923
|
multiline: f.kind === "multiline",
|
|
5807
5924
|
inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
|
|
5808
5925
|
onChange: (v) => setValue(f.key, v),
|
|
5809
|
-
actions: /* @__PURE__ */ jsxs24(
|
|
5926
|
+
actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5810
5927
|
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,
|
|
5811
5928
|
secretKind ? /* @__PURE__ */ jsx26(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
|
|
5812
5929
|
existing ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
|
|
@@ -5825,7 +5942,7 @@ function ItemPane(props) {
|
|
|
5825
5942
|
onChange: (v) => setValue(f.key, v),
|
|
5826
5943
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
5827
5944
|
removeLabel: `Delete ${f.label}`,
|
|
5828
|
-
actions: /* @__PURE__ */ jsxs24(
|
|
5945
|
+
actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5829
5946
|
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,
|
|
5830
5947
|
/* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
|
|
5831
5948
|
] })
|
|
@@ -5857,7 +5974,7 @@ function ItemPane(props) {
|
|
|
5857
5974
|
i
|
|
5858
5975
|
)),
|
|
5859
5976
|
/* @__PURE__ */ jsx26(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
5860
|
-
/* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator), item, port, onEnrolled: onChanged }),
|
|
5977
|
+
/* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
5861
5978
|
item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
5862
5979
|
] }),
|
|
5863
5980
|
/* @__PURE__ */ jsx26(VaultSection, { children: /* @__PURE__ */ jsx26(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
|
|
@@ -5890,12 +6007,12 @@ function ItemPane(props) {
|
|
|
5890
6007
|
) : null,
|
|
5891
6008
|
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}`)),
|
|
5892
6009
|
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)),
|
|
5893
|
-
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "
|
|
6010
|
+
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
|
|
5894
6011
|
]
|
|
5895
6012
|
}
|
|
5896
6013
|
),
|
|
5897
6014
|
filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: true }) : null
|
|
5898
|
-
] }) : item ? /* @__PURE__ */ jsxs24(
|
|
6015
|
+
] }) : item ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5899
6016
|
/* @__PURE__ */ jsxs24(VaultSection, { children: [
|
|
5900
6017
|
declared.map((f) => {
|
|
5901
6018
|
if (f.storage === "metadata") {
|
|
@@ -5904,11 +6021,15 @@ function ItemPane(props) {
|
|
|
5904
6021
|
}
|
|
5905
6022
|
const field = item.fields.find((x) => x.key === f.key);
|
|
5906
6023
|
if (isRecoveryCodesField(f)) return /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
|
|
5907
|
-
return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field }, field.id) : null;
|
|
6024
|
+
return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field, onTurnOn: turnOnOne(field) }, field.id) : null;
|
|
5908
6025
|
}),
|
|
5909
|
-
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx26(SecretRow, { port, item, field: f }, f.id)),
|
|
6026
|
+
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)),
|
|
5910
6027
|
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" }),
|
|
5911
|
-
item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) :
|
|
6028
|
+
item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
|
|
6029
|
+
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6030
|
+
// which would invite replacing a working two-factor secret.
|
|
6031
|
+
/* @__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" }) })
|
|
6032
|
+
) : /* @__PURE__ */ jsx26(AddRow, { label: "One-time password", onAdd: canEdit ? () => onMode("edit") : null, children: "Set up" }),
|
|
5912
6033
|
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
5913
6034
|
] }),
|
|
5914
6035
|
/* @__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" }) }),
|
|
@@ -5940,7 +6061,7 @@ function subtitleOf(item, withOwner) {
|
|
|
5940
6061
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
5941
6062
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
5942
6063
|
}
|
|
5943
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header }) {
|
|
6064
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
|
|
5944
6065
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
5945
6066
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
5946
6067
|
const ordered = [...pinned, ...rest];
|
|
@@ -5959,7 +6080,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
5959
6080
|
listRef.current?.querySelector(`[data-item="${next.id}"]`)?.scrollIntoView({ block: "nearest" });
|
|
5960
6081
|
}
|
|
5961
6082
|
};
|
|
5962
|
-
const mixedOwners = new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6083
|
+
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
5963
6084
|
const row = (i) => /* @__PURE__ */ jsx27(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
|
|
5964
6085
|
const sortLabel = SORTS2.find((s) => s.value === sort)?.label ?? "Name";
|
|
5965
6086
|
return /* @__PURE__ */ jsxs25("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
@@ -6112,7 +6233,7 @@ function refusalText(reason) {
|
|
|
6112
6233
|
// src/lists/RestorePanel.tsx
|
|
6113
6234
|
import { useEffect as useEffect18, useState as useState28 } from "react";
|
|
6114
6235
|
import { Button as Button23 } from "@ai-matrx/design-system/controls";
|
|
6115
|
-
import { Fragment as
|
|
6236
|
+
import { Fragment as Fragment17, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6116
6237
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6117
6238
|
function RestorePanel({ lists, item, restore, onClose }) {
|
|
6118
6239
|
const [preview, setPreview] = useState28(null);
|
|
@@ -6157,7 +6278,7 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6157
6278
|
title: `Restore "${item.name}"`,
|
|
6158
6279
|
size: "md",
|
|
6159
6280
|
onClose,
|
|
6160
|
-
footer: /* @__PURE__ */ jsxs26(
|
|
6281
|
+
footer: /* @__PURE__ */ jsxs26(Fragment17, { children: [
|
|
6161
6282
|
/* @__PURE__ */ jsx28(Button23, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
|
|
6162
6283
|
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" })
|
|
6163
6284
|
] }),
|
|
@@ -6177,6 +6298,9 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6177
6298
|
|
|
6178
6299
|
// src/lists/TrashView.tsx
|
|
6179
6300
|
import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
6301
|
+
function trashLineOf(item) {
|
|
6302
|
+
return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
|
|
6303
|
+
}
|
|
6180
6304
|
function TrashView({ port, deleted, query, header, onChanged }) {
|
|
6181
6305
|
const confirmed = useConfirmed();
|
|
6182
6306
|
const [busyId, setBusyId] = useState29(null);
|
|
@@ -6188,7 +6312,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6188
6312
|
setMessage(null);
|
|
6189
6313
|
try {
|
|
6190
6314
|
const r = await confirmed(() => port.lists.restore(item, deletionId));
|
|
6191
|
-
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files.
|
|
6315
|
+
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.` });
|
|
6192
6316
|
onChanged();
|
|
6193
6317
|
return r;
|
|
6194
6318
|
} catch (e) {
|
|
@@ -6206,7 +6330,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6206
6330
|
/* @__PURE__ */ jsxs27("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
|
|
6207
6331
|
/* @__PURE__ */ jsxs27("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6208
6332
|
/* @__PURE__ */ jsx29("span", { className: "truncate text-sm text-foreground", children: item.name }),
|
|
6209
|
-
/* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children:
|
|
6333
|
+
/* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
|
|
6210
6334
|
] }),
|
|
6211
6335
|
/* @__PURE__ */ jsx29(Button24, { variant: "outline", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6212
6336
|
] }, item.id)
|
|
@@ -6497,10 +6621,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6497
6621
|
title: "Send securely",
|
|
6498
6622
|
size: "md",
|
|
6499
6623
|
onClose,
|
|
6500
|
-
footer: /* @__PURE__ */ jsxs29(
|
|
6501
|
-
/* @__PURE__ */ jsx31("div", { className: "w-full sm:w-auto sm:min-w-0 sm:flex-1", children: /* @__PURE__ */ jsx31(StatusLine, { error, notice }) }),
|
|
6624
|
+
footer: /* @__PURE__ */ jsxs29(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx31(StatusLine, { error, notice }) : null, children: [
|
|
6502
6625
|
sameChannelSent && !error ? /* @__PURE__ */ jsx31(Badge8, { tone: "warning", children: "Both by email" }) : null,
|
|
6503
|
-
/* @__PURE__ */ jsx31(Button26, { variant: "quiet",
|
|
6626
|
+
/* @__PURE__ */ jsx31(Button26, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
6504
6627
|
/* @__PURE__ */ jsx31(Button26, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
|
|
6505
6628
|
] }),
|
|
6506
6629
|
children: [
|
|
@@ -6653,7 +6776,7 @@ function addPasskeyFailure(message2) {
|
|
|
6653
6776
|
var isRevoked = (d) => d.revokedAt !== null;
|
|
6654
6777
|
|
|
6655
6778
|
// src/devices/DevicesPanel.tsx
|
|
6656
|
-
import { Fragment as
|
|
6779
|
+
import { Fragment as Fragment18, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6657
6780
|
var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
6658
6781
|
function ErrorLine2({ text }) {
|
|
6659
6782
|
return text ? /* @__PURE__ */ jsx32("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
|
|
@@ -6784,7 +6907,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6784
6907
|
};
|
|
6785
6908
|
const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
|
|
6786
6909
|
const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
|
|
6787
|
-
const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(
|
|
6910
|
+
const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
|
|
6788
6911
|
/* @__PURE__ */ jsx32(Button27, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
|
|
6789
6912
|
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
|
|
6790
6913
|
] });
|
|
@@ -6792,7 +6915,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6792
6915
|
"This link names no key. Start again from ",
|
|
6793
6916
|
where,
|
|
6794
6917
|
"."
|
|
6795
|
-
] }) }) : /* @__PURE__ */ jsxs30(
|
|
6918
|
+
] }) }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
|
|
6796
6919
|
/* @__PURE__ */ jsxs30(VaultSection, { title: "What is asking", children: [
|
|
6797
6920
|
/* @__PURE__ */ jsx32(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
|
|
6798
6921
|
name ? /* @__PURE__ */ jsx32(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx32("span", { className: "block truncate", children: name }) }) : null,
|
|
@@ -7092,7 +7215,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7092
7215
|
}
|
|
7093
7216
|
|
|
7094
7217
|
// src/native/NativeImportPanel.tsx
|
|
7095
|
-
import { Fragment as
|
|
7218
|
+
import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
7096
7219
|
var TONE = {
|
|
7097
7220
|
eligible: "success",
|
|
7098
7221
|
committed: "success",
|
|
@@ -7136,16 +7259,16 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7136
7259
|
const yes = await confirm12({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
|
|
7137
7260
|
if (yes) await flow.confirm();
|
|
7138
7261
|
};
|
|
7139
|
-
const footer = preview ? /* @__PURE__ */ jsxs31(
|
|
7262
|
+
const footer = preview ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7140
7263
|
/* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
|
|
7141
7264
|
/* @__PURE__ */ jsxs31(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
|
|
7142
7265
|
"Import ",
|
|
7143
7266
|
ready
|
|
7144
7267
|
] })
|
|
7145
|
-
] }) : status ? active ? /* @__PURE__ */ jsxs31(
|
|
7268
|
+
] }) : status ? active ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7146
7269
|
/* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
|
|
7147
7270
|
/* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
|
|
7148
|
-
] }) : /* @__PURE__ */ jsxs31(
|
|
7271
|
+
] }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7149
7272
|
/* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: flow.reset, children: "New file" }),
|
|
7150
7273
|
/* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" })
|
|
7151
7274
|
] }) : /* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: onClose, children: "Close" });
|
|
@@ -7184,7 +7307,7 @@ import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
|
7184
7307
|
// src/extension/CaptureCard.tsx
|
|
7185
7308
|
import { useState as useState35, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
7186
7309
|
import { Button as Button29, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
|
|
7187
|
-
import { Fragment as
|
|
7310
|
+
import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7188
7311
|
var SEARCH_FROM = 4;
|
|
7189
7312
|
function CaptureCard({ capture, onChanged }) {
|
|
7190
7313
|
const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
|
|
@@ -7217,7 +7340,7 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7217
7340
|
] }),
|
|
7218
7341
|
/* @__PURE__ */ jsx34(Button29, { variant: "quiet", icon: /* @__PURE__ */ jsx34(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
|
|
7219
7342
|
] }),
|
|
7220
|
-
prompt.unavailable ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs32(
|
|
7343
|
+
prompt.unavailable ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs32(Fragment20, { children: [
|
|
7221
7344
|
existing.length > 0 ? /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1", children: [
|
|
7222
7345
|
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,
|
|
7223
7346
|
/* @__PURE__ */ jsxs32("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
|
|
@@ -7323,7 +7446,7 @@ import { useState as useState37 } from "react";
|
|
|
7323
7446
|
import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
|
|
7324
7447
|
import { Button as Button31 } from "@ai-matrx/design-system/controls";
|
|
7325
7448
|
import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
|
|
7326
|
-
import { Fragment as
|
|
7449
|
+
import { Fragment as Fragment21, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
7327
7450
|
var HOLD_MS = 6e4;
|
|
7328
7451
|
function PageGenerator({ fields }) {
|
|
7329
7452
|
const limits = useGeneratorLimitsSource();
|
|
@@ -7374,12 +7497,12 @@ function PageGenerator({ fields }) {
|
|
|
7374
7497
|
}
|
|
7375
7498
|
};
|
|
7376
7499
|
const value = held.value;
|
|
7377
|
-
return /* @__PURE__ */ jsxs34(
|
|
7500
|
+
return /* @__PURE__ */ jsxs34(Fragment21, { children: [
|
|
7378
7501
|
/* @__PURE__ */ jsx36(
|
|
7379
7502
|
VaultRow,
|
|
7380
7503
|
{
|
|
7381
7504
|
label: "New password",
|
|
7382
|
-
actions: /* @__PURE__ */ jsxs34(
|
|
7505
|
+
actions: /* @__PURE__ */ jsxs34(Fragment21, { children: [
|
|
7383
7506
|
value ? /* @__PURE__ */ jsx36(Button31, { variant: "quiet", icon: /* @__PURE__ */ jsx36(CopyIcon7, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
|
|
7384
7507
|
/* @__PURE__ */ jsxs34(Popover2, { open, onOpenChange: setOpen, children: [
|
|
7385
7508
|
/* @__PURE__ */ jsx36(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx36(Button31, { variant: "outline", icon: /* @__PURE__ */ jsx36(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
|
|
@@ -7756,8 +7879,33 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7756
7879
|
},
|
|
7757
7880
|
[loc, move]
|
|
7758
7881
|
);
|
|
7882
|
+
const keyState = useRef19({ loc, go });
|
|
7883
|
+
keyState.current = { loc, go };
|
|
7884
|
+
useEffect23(() => {
|
|
7885
|
+
const onKey = (e) => {
|
|
7886
|
+
if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
7887
|
+
const root = rootRef.current;
|
|
7888
|
+
const at = document.activeElement;
|
|
7889
|
+
if (!root || at && at !== document.body && !root.contains(at)) return;
|
|
7890
|
+
if (at instanceof HTMLElement && (at.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(at.tagName))) return;
|
|
7891
|
+
if (document.querySelector('[role="dialog"], [role="alertdialog"]')) return;
|
|
7892
|
+
const { loc: here, go: to } = keyState.current;
|
|
7893
|
+
if (e.key === "/") {
|
|
7894
|
+
const search = root.querySelector('input[aria-label^="Search"]');
|
|
7895
|
+
if (!search) return;
|
|
7896
|
+
e.preventDefault();
|
|
7897
|
+
search.focus();
|
|
7898
|
+
} else if (e.key === "Escape" && here.itemId && here.mode === "view" && !here.panel) {
|
|
7899
|
+
e.preventDefault();
|
|
7900
|
+
to({ itemId: null, mode: "view", panel: null });
|
|
7901
|
+
}
|
|
7902
|
+
};
|
|
7903
|
+
document.addEventListener("keydown", onKey);
|
|
7904
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
7905
|
+
}, []);
|
|
7759
7906
|
const knobsRef = useRef19(host.knobs);
|
|
7760
7907
|
knobsRef.current = host.knobs;
|
|
7908
|
+
const [signedOut, setSignedOut] = useState40(false);
|
|
7761
7909
|
const load = useCallback5(() => {
|
|
7762
7910
|
setError(null);
|
|
7763
7911
|
port.load().then((s) => {
|
|
@@ -7768,7 +7916,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7768
7916
|
(rows) => setDeleted([...s.deleted, ...rows.filter((r) => !s.deleted.some((d) => d.id === r.id))]),
|
|
7769
7917
|
() => void 0
|
|
7770
7918
|
);
|
|
7771
|
-
}).catch((e) =>
|
|
7919
|
+
}).catch((e) => {
|
|
7920
|
+
setSignedOut(e?.status === 401);
|
|
7921
|
+
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
7922
|
+
});
|
|
7772
7923
|
port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
|
|
7773
7924
|
knobsRef.current?.().catch(() => void 0);
|
|
7774
7925
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
@@ -7782,6 +7933,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7782
7933
|
const orgs = snap?.organizations ?? [];
|
|
7783
7934
|
const definitions = snap?.definitions ?? [];
|
|
7784
7935
|
const inThisVault = useMemo6(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
|
|
7936
|
+
const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
7785
7937
|
const views = useMemo6(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
|
|
7786
7938
|
const visible = useMemo6(() => {
|
|
7787
7939
|
const filtered = inThisVault.filter((i) => {
|
|
@@ -7822,8 +7974,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7822
7974
|
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: [
|
|
7823
7975
|
/* @__PURE__ */ jsx39(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
7824
7976
|
/* @__PURE__ */ jsx39("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
|
|
7825
|
-
/* @__PURE__ */ jsx39("div", { className: "max-w-xs text-muted-foreground", children: plainLoadError(error) }),
|
|
7826
|
-
/* @__PURE__ */
|
|
7977
|
+
/* @__PURE__ */ jsx39("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
|
|
7978
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex gap-2", children: [
|
|
7979
|
+
signedOut && host.signIn ? /* @__PURE__ */ jsx39(Button33, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
|
|
7980
|
+
/* @__PURE__ */ jsx39(Button33, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
|
|
7981
|
+
] })
|
|
7827
7982
|
] });
|
|
7828
7983
|
}
|
|
7829
7984
|
if (!snap) {
|
|
@@ -7903,6 +8058,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7903
8058
|
{
|
|
7904
8059
|
title,
|
|
7905
8060
|
items: visible,
|
|
8061
|
+
showOwner: vaultMixesOwners,
|
|
7906
8062
|
definitions,
|
|
7907
8063
|
port,
|
|
7908
8064
|
selectedId: loc.itemId,
|
|
@@ -8675,6 +8831,7 @@ async function readNativeImportLimits(api, organizationId) {
|
|
|
8675
8831
|
var recoveryOf = (w) => w.lifecycle?.vault_recovery;
|
|
8676
8832
|
var isDeleted = (w) => recoveryOf(w)?.state === "deleted";
|
|
8677
8833
|
var MATCH_MODES2 = ["host", "domain", "exact", "never"];
|
|
8834
|
+
var FIELD_WORDS = { totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
|
|
8678
8835
|
var handlingOf = (v) => v === "visible" || v === "sealed" ? v : "revealable";
|
|
8679
8836
|
function fieldOf(w, def) {
|
|
8680
8837
|
const declared = def?.fields.find((f) => f.key === w.field_key);
|
|
@@ -8682,7 +8839,7 @@ function fieldOf(w, def) {
|
|
|
8682
8839
|
return {
|
|
8683
8840
|
id: w.id,
|
|
8684
8841
|
key: w.field_key,
|
|
8685
|
-
label: declared?.label ?? humanize(w.field_key),
|
|
8842
|
+
label: declared?.label ?? FIELD_WORDS[w.field_key] ?? humanize(w.field_key),
|
|
8686
8843
|
kind: declared?.kind ?? (handling === "visible" ? "text" : "secret"),
|
|
8687
8844
|
handling,
|
|
8688
8845
|
editable: w.editable ?? true,
|
|
@@ -8791,7 +8948,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
8791
8948
|
lists.forEach((l, i) => {
|
|
8792
8949
|
const sharedList = i === lists.length - 1;
|
|
8793
8950
|
for (const w of l.items) {
|
|
8794
|
-
if (seen.has(w.id) || deleted.has(w.id)) continue;
|
|
8951
|
+
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) continue;
|
|
8795
8952
|
const owner = sharedList ? orgOf(w.organization_id, null, false) : orgOf(w.organization_id, w.user_id, i === 0);
|
|
8796
8953
|
const item = itemOf(w, sharedList && !w.organization_id ? { kind: "shared", label: "Shared with me", organizationId: null } : owner, defs, auth);
|
|
8797
8954
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
@@ -8900,8 +9057,11 @@ function createVaultKnobs(client, address) {
|
|
|
8900
9057
|
}
|
|
8901
9058
|
export {
|
|
8902
9059
|
CATEGORIES,
|
|
9060
|
+
CONFIRM_RETURN_KEY,
|
|
8903
9061
|
DEFAULT_LOCATION,
|
|
8904
9062
|
GenerateButton,
|
|
9063
|
+
HIDDEN_ITEM_TAG,
|
|
9064
|
+
IdentityGate,
|
|
8905
9065
|
LOCKED_MESSAGE,
|
|
8906
9066
|
VaultApp,
|
|
8907
9067
|
VaultLockedError,
|
|
@@ -8912,12 +9072,16 @@ export {
|
|
|
8912
9072
|
createVaultKnobs,
|
|
8913
9073
|
guardPort,
|
|
8914
9074
|
inferFromUrl,
|
|
9075
|
+
isHiddenItem,
|
|
8915
9076
|
locationFromParams,
|
|
8916
9077
|
locationToParams,
|
|
8917
9078
|
loginSiteOf,
|
|
8918
9079
|
matchesQuery,
|
|
8919
9080
|
needsRecentSignIn,
|
|
8920
9081
|
parseDefinitions,
|
|
8921
|
-
|
|
9082
|
+
siteDomainOf,
|
|
9083
|
+
sortItems,
|
|
9084
|
+
useConfirmed,
|
|
9085
|
+
wasCancelled
|
|
8922
9086
|
};
|
|
8923
9087
|
//# sourceMappingURL=index.js.map
|