@ai-matrx/vault 0.1.5 → 0.1.7
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 +18 -0
- package/README.md +1 -1
- package/dist/index.cjs +378 -277
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +166 -65
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -115,9 +115,28 @@ var Ctx = createContext(() => void 0);
|
|
|
115
115
|
function useNotify() {
|
|
116
116
|
return useContext(Ctx);
|
|
117
117
|
}
|
|
118
|
+
async function copyValue(text, label, options, deps) {
|
|
119
|
+
const secret = options.secret ?? true;
|
|
120
|
+
if (deps.clipboard) {
|
|
121
|
+
try {
|
|
122
|
+
await deps.clipboard.copy(text, { secret });
|
|
123
|
+
deps.notify(`${label} copied`, "success");
|
|
124
|
+
return true;
|
|
125
|
+
} catch (e) {
|
|
126
|
+
deps.notify(e instanceof Error && e.message ? e.message : `${label} could not be copied`, "error");
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return copyText(text, { successMessage: `${label} copied`, failureMessage: `${label} could not be copied`, notify: (m, k) => deps.notify(m, k === "error" ? "error" : "success") });
|
|
131
|
+
}
|
|
132
|
+
var ClipboardCtx = createContext(void 0);
|
|
133
|
+
function ClipboardProvider({ clipboard, children }) {
|
|
134
|
+
return /* @__PURE__ */ jsx(ClipboardCtx.Provider, { value: clipboard, children });
|
|
135
|
+
}
|
|
118
136
|
function useCopy() {
|
|
119
137
|
const notify = useNotify();
|
|
120
|
-
|
|
138
|
+
const clipboard = useContext(ClipboardCtx);
|
|
139
|
+
return useCallback((text, label, options = {}) => copyValue(text, label, options, { clipboard, notify }), [notify, clipboard]);
|
|
121
140
|
}
|
|
122
141
|
function NoticeProvider({ notify, children }) {
|
|
123
142
|
const [shown, setShown] = useState(null);
|
|
@@ -494,8 +513,16 @@ import { Badge, Button as Button2, Field as Field2, Textarea } from "@ai-matrx/d
|
|
|
494
513
|
import { cn as cn3 } from "@ai-matrx/design-system";
|
|
495
514
|
|
|
496
515
|
// src/hooks.ts
|
|
497
|
-
import { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
|
|
498
|
-
|
|
516
|
+
import { createContext as createContext3, createElement, useCallback as useCallback2, useContext as useContext3, useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
|
|
517
|
+
var DEFAULT_REVEAL_MS = 2e4;
|
|
518
|
+
var RevealMs = createContext3(DEFAULT_REVEAL_MS);
|
|
519
|
+
function RevealSecondsProvider({ seconds, children }) {
|
|
520
|
+
const ms = seconds !== void 0 && Number.isFinite(seconds) && seconds > 0 ? seconds * 1e3 : DEFAULT_REVEAL_MS;
|
|
521
|
+
return createElement(RevealMs.Provider, { value: ms }, children);
|
|
522
|
+
}
|
|
523
|
+
function useTransientSecret(given) {
|
|
524
|
+
const fromHost = useContext3(RevealMs);
|
|
525
|
+
const ms = given ?? fromHost;
|
|
499
526
|
const [value, setValue] = useState3(null);
|
|
500
527
|
const timer2 = useRef3(null);
|
|
501
528
|
const clear = useCallback2(() => {
|
|
@@ -531,12 +558,12 @@ function useElementWidth(ref) {
|
|
|
531
558
|
}
|
|
532
559
|
|
|
533
560
|
// src/ui.tsx
|
|
534
|
-
import { createContext as
|
|
561
|
+
import { createContext as createContext4, useContext as useContext4, useEffect as useEffect4, useState as useState4 } from "react";
|
|
535
562
|
import { Dialog as Dialog2, DialogContent as DialogContent2, DialogFooter, DialogHeader as DialogHeader2, DialogTitle as DialogTitle2 } from "@ai-matrx/design-system";
|
|
536
563
|
import { cn as cn2 } from "@ai-matrx/design-system";
|
|
537
564
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
538
|
-
var InPanel =
|
|
539
|
-
var Room =
|
|
565
|
+
var InPanel = createContext4(false);
|
|
566
|
+
var Room = createContext4(null);
|
|
540
567
|
var ROOMY_AT = 560;
|
|
541
568
|
function useRoomOf(ref) {
|
|
542
569
|
const [room, setRoom] = useState4(null);
|
|
@@ -553,7 +580,7 @@ function useRoomOf(ref) {
|
|
|
553
580
|
}
|
|
554
581
|
var RoomProvider = Room.Provider;
|
|
555
582
|
function Section({ title, actions, children, className }) {
|
|
556
|
-
const flat =
|
|
583
|
+
const flat = useContext4(InPanel);
|
|
557
584
|
return /* @__PURE__ */ jsxs4("section", { className: cn2("flex flex-col gap-1.5", className), children: [
|
|
558
585
|
title || actions ? /* @__PURE__ */ jsxs4("div", { className: "flex min-h-7 items-center justify-between gap-2 px-1", children: [
|
|
559
586
|
title ? /* @__PURE__ */ jsx4("h3", { className: "text-xs font-medium text-muted-foreground", children: title }) : /* @__PURE__ */ jsx4("span", {}),
|
|
@@ -568,7 +595,7 @@ var ROW_GRID = {
|
|
|
568
595
|
viewport: "grid-cols-[5.75rem_minmax(0,1fr)_auto] gap-x-2 px-3 sm:grid-cols-[9rem_minmax(0,1fr)_auto] sm:gap-x-3 sm:px-4"
|
|
569
596
|
};
|
|
570
597
|
function Row({ label, hint, children, actions, top = false, className }) {
|
|
571
|
-
const room =
|
|
598
|
+
const room = useContext4(Room);
|
|
572
599
|
return /* @__PURE__ */ jsxs4("div", { className: cn2("grid min-h-11 py-1", ROW_GRID[room ?? "viewport"], top ? "items-start" : "items-center", className), children: [
|
|
573
600
|
/* @__PURE__ */ jsxs4("div", { className: cn2("flex min-w-0 flex-col text-xs leading-tight text-muted-foreground", top && "pt-2.5"), children: [
|
|
574
601
|
/* @__PURE__ */ jsx4("span", { className: room === "roomy" ? "truncate" : room === "compact" ? "line-clamp-2 break-words" : "line-clamp-2 break-words sm:truncate", children: label }),
|
|
@@ -593,12 +620,7 @@ function formatBytes(n) {
|
|
|
593
620
|
if (n < 1024 * 1024) return `${(n / 1024).toFixed(n < 10 * 1024 ? 1 : 0)} KB`;
|
|
594
621
|
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
595
622
|
}
|
|
596
|
-
|
|
597
|
-
if (!iso) return "";
|
|
598
|
-
const d = new Date(iso);
|
|
599
|
-
if (Number.isNaN(d.getTime())) return iso;
|
|
600
|
-
return d.toLocaleString(void 0, withTime ? { year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "2-digit" } : { year: "numeric", month: "short", day: "numeric" });
|
|
601
|
-
}
|
|
623
|
+
var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
|
|
602
624
|
|
|
603
625
|
// src/FieldRows.tsx
|
|
604
626
|
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
@@ -610,7 +632,7 @@ function SecretText({ value, multiline }) {
|
|
|
610
632
|
var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
611
633
|
function SecretRow({ port, item, field, extra }) {
|
|
612
634
|
const confirmed = useConfirmed();
|
|
613
|
-
const
|
|
635
|
+
const copyValue2 = useCopy();
|
|
614
636
|
const secret = useTransientSecret();
|
|
615
637
|
const [plain, setPlain] = useState5(null);
|
|
616
638
|
const [busy, setBusy] = useState5(false);
|
|
@@ -651,7 +673,7 @@ function SecretRow({ port, item, field, extra }) {
|
|
|
651
673
|
}
|
|
652
674
|
async function copy() {
|
|
653
675
|
const v = await fetchValue();
|
|
654
|
-
if (v !== null) await
|
|
676
|
+
if (v !== null) await copyValue2(v, field.label, { secret: !visible });
|
|
655
677
|
}
|
|
656
678
|
const multiline = field.kind === "multiline";
|
|
657
679
|
const shown = visible ? plain : secret.value;
|
|
@@ -670,7 +692,7 @@ function SecretRow({ port, item, field, extra }) {
|
|
|
670
692
|
);
|
|
671
693
|
}
|
|
672
694
|
function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
|
|
673
|
-
const
|
|
695
|
+
const copyValue2 = useCopy();
|
|
674
696
|
const isUrl = /^https?:\/\//i.test(value);
|
|
675
697
|
return /* @__PURE__ */ jsx5(
|
|
676
698
|
Row,
|
|
@@ -681,7 +703,7 @@ function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
|
|
|
681
703
|
actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
682
704
|
extra,
|
|
683
705
|
isUrl && openUrl ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: /* @__PURE__ */ jsx5(ExternalGlyph, {}), "aria-label": `Open ${value}`, onClick: () => openUrl(value) }) : null,
|
|
684
|
-
/* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: /* @__PURE__ */ jsx5(CopyGlyph, {}), "aria-label": `Copy ${typeof label === "string" ? label : "value"}`, onClick: () => void
|
|
706
|
+
/* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: /* @__PURE__ */ jsx5(CopyGlyph, {}), "aria-label": `Copy ${typeof label === "string" ? label : "value"}`, onClick: () => void copyValue2(value, typeof label === "string" && label ? label : "Value", { secret: false }) })
|
|
685
707
|
] }),
|
|
686
708
|
children: isUrl && openUrl ? (
|
|
687
709
|
// A real link (right-click, copy link address, open in a new tab); a click goes through the host's opener.
|
|
@@ -738,6 +760,9 @@ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
|
|
|
738
760
|
);
|
|
739
761
|
}
|
|
740
762
|
|
|
763
|
+
// src/activity/HistoryPanel.tsx
|
|
764
|
+
import { formatAbsoluteDate as formatAbsoluteDate2 } from "@ai-matrx/kit/format";
|
|
765
|
+
|
|
741
766
|
// src/activity/logic.ts
|
|
742
767
|
import { formatRelativeTime } from "@ai-matrx/kit/format";
|
|
743
768
|
|
|
@@ -789,7 +814,7 @@ function matchesQuery(item, query) {
|
|
|
789
814
|
return [item.name, item.definitionLabel, ...item.tags, ...item.loginUrls, ...item.custom.map((c) => `${c.label} ${c.value}`)].some((h) => h.toLowerCase().includes(q));
|
|
790
815
|
}
|
|
791
816
|
var isAuthenticatorStorage = (key) => key === "totp_seed" || key.startsWith("totp_") || key === "authenticator_last_time_step";
|
|
792
|
-
function
|
|
817
|
+
function loginSiteOf(item) {
|
|
793
818
|
const raw = item.loginUrls[0];
|
|
794
819
|
if (!raw) return "";
|
|
795
820
|
try {
|
|
@@ -803,7 +828,7 @@ function sortItems(items, sort) {
|
|
|
803
828
|
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
804
829
|
if (sort === "name") return out.sort(byName);
|
|
805
830
|
if (sort === "website") return out.sort((a, b) => {
|
|
806
|
-
const x =
|
|
831
|
+
const x = loginSiteOf(a), y = loginSiteOf(b);
|
|
807
832
|
return x && y ? x.localeCompare(y) || byName(a, b) : x ? -1 : y ? 1 : byName(a, b);
|
|
808
833
|
});
|
|
809
834
|
if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
@@ -1195,6 +1220,7 @@ var HistoryChangedError = class extends Error {
|
|
|
1195
1220
|
import { useEffect as useEffect6, useRef as useRef4, useState as useState6 } from "react";
|
|
1196
1221
|
import { Button as Button3 } from "@ai-matrx/design-system/controls";
|
|
1197
1222
|
import { cn as cn4 } from "@ai-matrx/design-system";
|
|
1223
|
+
import { formatAbsoluteDate } from "@ai-matrx/kit/format";
|
|
1198
1224
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1199
1225
|
var PAGE = 50;
|
|
1200
1226
|
var MAX = 500;
|
|
@@ -1231,7 +1257,7 @@ function ActivityPanel({ item, port, onClose }) {
|
|
|
1231
1257
|
day.entries.map((entry) => ({ entry, s: auditSentence(entry, item, me) })),
|
|
1232
1258
|
(r) => `${r.s.what}|${r.s.who ?? ""}`
|
|
1233
1259
|
).map(({ row: { entry, s }, times }) => {
|
|
1234
|
-
return /* @__PURE__ */ jsxs6("div", { className: "flex min-h-9 items-center gap-1.5 px-3 text-sm sm:px-4", title:
|
|
1260
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex min-h-9 items-center gap-1.5 px-3 text-sm sm:px-4", title: formatAbsoluteDate(entry.at, void 0, ""), children: [
|
|
1235
1261
|
/* @__PURE__ */ jsx6("span", { className: cn4("truncate", s.refused ? "text-destructive" : "text-foreground"), children: s.what }),
|
|
1236
1262
|
/* @__PURE__ */ jsxs6("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
1237
1263
|
times > 1 ? ` \xB7 ${times} times` : "",
|
|
@@ -1316,7 +1342,7 @@ function HistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
|
1316
1342
|
page && (page.captureStartedAt || page.incomplete) ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-x-3 gap-y-1 px-1 text-xs", children: [
|
|
1317
1343
|
page.captureStartedAt ? /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
|
|
1318
1344
|
"Kept since ",
|
|
1319
|
-
|
|
1345
|
+
formatAbsoluteDate2(page.captureStartedAt, void 0, "")
|
|
1320
1346
|
] }) : null,
|
|
1321
1347
|
page.incomplete ? /* @__PURE__ */ jsx7("span", { className: "text-warning", children: "Some changes could not be read" }) : null
|
|
1322
1348
|
] }) : null
|
|
@@ -1327,9 +1353,9 @@ function HistoryPanel({ item, port, arg, onClose, onChanged }) {
|
|
|
1327
1353
|
function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, onError }) {
|
|
1328
1354
|
const confirmed = useConfirmed();
|
|
1329
1355
|
const secret = useTransientSecret();
|
|
1330
|
-
const
|
|
1356
|
+
const copyValue2 = useCopy();
|
|
1331
1357
|
const [busy, setBusy] = useState7(false);
|
|
1332
|
-
const when =
|
|
1358
|
+
const when = formatAbsoluteDate2(entry.recordedAt, void 0, "");
|
|
1333
1359
|
async function read() {
|
|
1334
1360
|
if (secret.value !== null) return secret.value;
|
|
1335
1361
|
setBusy(true);
|
|
@@ -1350,7 +1376,7 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
|
|
|
1350
1376
|
}
|
|
1351
1377
|
async function copy() {
|
|
1352
1378
|
const v = await read();
|
|
1353
|
-
if (v !== null) await
|
|
1379
|
+
if (v !== null) await copyValue2(v, `Earlier ${label.toLowerCase()}`);
|
|
1354
1380
|
}
|
|
1355
1381
|
async function restore() {
|
|
1356
1382
|
const yes = await confirm({
|
|
@@ -1491,11 +1517,11 @@ function authenticatorName(current, parsed) {
|
|
|
1491
1517
|
if (name && !PLACEHOLDER_NAMES.includes(name.toLowerCase())) return name;
|
|
1492
1518
|
return parsed.issuer || parsed.account || name || "One-time password";
|
|
1493
1519
|
}
|
|
1494
|
-
function matchIssuerToSite(issuer, candidates,
|
|
1520
|
+
function matchIssuerToSite(issuer, candidates, siteOf) {
|
|
1495
1521
|
const key = (issuer ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1496
1522
|
if (key.length < 2) return null;
|
|
1497
1523
|
for (const c of candidates) {
|
|
1498
|
-
const host =
|
|
1524
|
+
const host = siteOf(c).toLowerCase();
|
|
1499
1525
|
if (!host) continue;
|
|
1500
1526
|
const labels = host.split(".");
|
|
1501
1527
|
if (labels.some((l) => l.replace(/[^a-z0-9]/g, "") === key)) return c;
|
|
@@ -1535,13 +1561,13 @@ function CountdownRing({ remaining, period, loading = false, className }) {
|
|
|
1535
1561
|
}
|
|
1536
1562
|
function useCopied() {
|
|
1537
1563
|
const [copied, setCopied] = useState8(false);
|
|
1538
|
-
const
|
|
1564
|
+
const copyValue2 = useCopy();
|
|
1539
1565
|
const t = useRef6(null);
|
|
1540
1566
|
useEffect8(() => () => void (t.current && clearTimeout(t.current)), []);
|
|
1541
1567
|
return {
|
|
1542
1568
|
copied,
|
|
1543
1569
|
copy: async (code) => {
|
|
1544
|
-
const ok = await
|
|
1570
|
+
const ok = await copyValue2(code, "One-time code");
|
|
1545
1571
|
if (!ok) return;
|
|
1546
1572
|
setCopied(true);
|
|
1547
1573
|
if (t.current) clearTimeout(t.current);
|
|
@@ -2116,7 +2142,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2116
2142
|
const recognise = (p) => {
|
|
2117
2143
|
if (!nameTouched) setName((n) => authenticatorName(n, p));
|
|
2118
2144
|
if (!targetChosen) {
|
|
2119
|
-
const match = matchIssuerToSite(p.issuer, candidates,
|
|
2145
|
+
const match = matchIssuerToSite(p.issuer, candidates, loginSiteOf);
|
|
2120
2146
|
setTarget(match ? match.id : NEW);
|
|
2121
2147
|
}
|
|
2122
2148
|
};
|
|
@@ -2194,7 +2220,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2194
2220
|
value: target,
|
|
2195
2221
|
disabled: busy || created !== null,
|
|
2196
2222
|
"aria-label": "Add to",
|
|
2197
|
-
options: [{ value: NEW, label: "New login" }, ...candidates.map((c) => ({ value: c.id, label:
|
|
2223
|
+
options: [{ value: NEW, label: "New login" }, ...candidates.map((c) => ({ value: c.id, label: loginSiteOf(c) ? `${c.name} \xB7 ${loginSiteOf(c)}` : c.name }))],
|
|
2198
2224
|
onValueChange: (v) => {
|
|
2199
2225
|
setTarget(v);
|
|
2200
2226
|
setTargetChosen(true);
|
|
@@ -2356,7 +2382,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, on
|
|
|
2356
2382
|
const Icon = definitionGlyph(item.definitionKey, family);
|
|
2357
2383
|
const canManage = item.capabilities.canManage || item.capabilities.canEdit;
|
|
2358
2384
|
if (a.removed) return null;
|
|
2359
|
-
const sub = a.error ?? [entry?.account,
|
|
2385
|
+
const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
|
|
2360
2386
|
return /* @__PURE__ */ jsxs12("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-3 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
|
|
2361
2387
|
/* @__PURE__ */ jsx12("button", { type: "button", onClick: onOpen, "aria-label": `Open ${item.name}`, tabIndex: -1, className: cn6("flex size-8 items-center justify-center rounded-lg bg-muted", a.enabled ? "text-foreground" : "text-disabled-foreground"), children: /* @__PURE__ */ jsx12(Icon, { className: "size-4" }) }),
|
|
2362
2388
|
/* @__PURE__ */ jsxs12("button", { type: "button", onClick: onOpen, className: "flex min-w-0 flex-col items-start rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [
|
|
@@ -2683,7 +2709,7 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2683
2709
|
}
|
|
2684
2710
|
|
|
2685
2711
|
// src/generator/PasswordGenerator.tsx
|
|
2686
|
-
import { createContext as
|
|
2712
|
+
import { createContext as createContext5, useContext as useContext5, useEffect as useEffect12, useRef as useRef10, useState as useState15 } from "react";
|
|
2687
2713
|
import { Popover, PopoverContent, PopoverTrigger, cn as cn7 } from "@ai-matrx/design-system";
|
|
2688
2714
|
import { Button as Button11, NumberStepper, SegmentedControl as SegmentedControl2, Select as Select4, Switch as Switch2 } from "@ai-matrx/design-system/controls";
|
|
2689
2715
|
|
|
@@ -2744,12 +2770,12 @@ function strengthOf(bits) {
|
|
|
2744
2770
|
|
|
2745
2771
|
// src/generator/PasswordGenerator.tsx
|
|
2746
2772
|
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2747
|
-
var LimitsCtx =
|
|
2773
|
+
var LimitsCtx = createContext5(null);
|
|
2748
2774
|
function GeneratorLimitsProvider({ resolve: resolve2, children }) {
|
|
2749
2775
|
return /* @__PURE__ */ jsx14(LimitsCtx.Provider, { value: resolve2 ?? null, children });
|
|
2750
2776
|
}
|
|
2751
2777
|
function useGeneratorLimitsSource() {
|
|
2752
|
-
return
|
|
2778
|
+
return useContext5(LimitsCtx);
|
|
2753
2779
|
}
|
|
2754
2780
|
var MASK3 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
2755
2781
|
function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
@@ -2759,7 +2785,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2759
2785
|
const [candidate, setCandidate] = useState15(null);
|
|
2760
2786
|
const [revealed, setRevealed] = useState15(false);
|
|
2761
2787
|
const [note, setNote] = useState15(null);
|
|
2762
|
-
const
|
|
2788
|
+
const copyValue2 = useCopy();
|
|
2763
2789
|
const expiry = useRef10(null);
|
|
2764
2790
|
const drop = () => {
|
|
2765
2791
|
if (expiry.current) clearTimeout(expiry.current);
|
|
@@ -2819,7 +2845,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2819
2845
|
const strength = candidate ? strengthOf(candidate.bits) : null;
|
|
2820
2846
|
const copy = async () => {
|
|
2821
2847
|
if (!candidate) return;
|
|
2822
|
-
const ok = await
|
|
2848
|
+
const ok = await copyValue2(candidate.value, "Generated password");
|
|
2823
2849
|
setNote(ok ? { tone: "success", text: "Copied. Your clipboard keeps it." } : { tone: "destructive", text: "Couldn\u2019t copy. Reveal it and copy by hand." });
|
|
2824
2850
|
};
|
|
2825
2851
|
const use = () => {
|
|
@@ -2930,6 +2956,45 @@ function importLimitsFrom(resolved) {
|
|
|
2930
2956
|
return out;
|
|
2931
2957
|
}
|
|
2932
2958
|
|
|
2959
|
+
// src/lock.ts
|
|
2960
|
+
import { useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
2961
|
+
var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
|
|
2962
|
+
var VaultLockedError = class extends Error {
|
|
2963
|
+
code = "vault_locked";
|
|
2964
|
+
constructor() {
|
|
2965
|
+
super(LOCKED_MESSAGE);
|
|
2966
|
+
this.name = "VaultLockedError";
|
|
2967
|
+
}
|
|
2968
|
+
};
|
|
2969
|
+
function guardPort(port, locked) {
|
|
2970
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
2971
|
+
const wrap = (target) => {
|
|
2972
|
+
const hit = cache.get(target);
|
|
2973
|
+
if (hit) return hit;
|
|
2974
|
+
const proxy = new Proxy(target, {
|
|
2975
|
+
get(obj2, key, receiver) {
|
|
2976
|
+
const value = Reflect.get(obj2, key, receiver);
|
|
2977
|
+
if (typeof value === "function") {
|
|
2978
|
+
return (...args) => {
|
|
2979
|
+
if (locked()) return Promise.reject(new VaultLockedError());
|
|
2980
|
+
return value.apply(obj2, args);
|
|
2981
|
+
};
|
|
2982
|
+
}
|
|
2983
|
+
if (value && typeof value === "object") return wrap(value);
|
|
2984
|
+
return value;
|
|
2985
|
+
}
|
|
2986
|
+
});
|
|
2987
|
+
cache.set(target, proxy);
|
|
2988
|
+
return proxy;
|
|
2989
|
+
};
|
|
2990
|
+
return wrap(port);
|
|
2991
|
+
}
|
|
2992
|
+
var NEVER = () => () => void 0;
|
|
2993
|
+
var UNLOCKED = () => false;
|
|
2994
|
+
function useLocked(lock) {
|
|
2995
|
+
return useSyncExternalStore2(lock ? lock.subscribe : NEVER, lock ? () => lock.locked() : UNLOCKED, UNLOCKED);
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2933
2998
|
// src/io/BackupPanel.tsx
|
|
2934
2999
|
import { useEffect as useEffect13, useRef as useRef11, useState as useState17 } from "react";
|
|
2935
3000
|
import { Button as Button13, Field as Field6, SegmentedControl as SegmentedControl3, Switch as Switch3 } from "@ai-matrx/design-system/controls";
|
|
@@ -4806,7 +4871,7 @@ var MASK4 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\
|
|
|
4806
4871
|
var say2 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
4807
4872
|
function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
4808
4873
|
const confirmed = useConfirmed();
|
|
4809
|
-
const
|
|
4874
|
+
const copyValue2 = useCopy();
|
|
4810
4875
|
const secret = useTransientSecret();
|
|
4811
4876
|
const [busy, setBusy] = useState21(false);
|
|
4812
4877
|
const [error, setError] = useState21(null);
|
|
@@ -4894,7 +4959,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
4894
4959
|
children: sealed ? /* @__PURE__ */ jsx21(Badge6, { icon: /* @__PURE__ */ jsx21(LockGlyph, {}), children: "Sealed" }) : codes ? /* @__PURE__ */ jsxs20("ul", { className: "flex flex-col gap-0.5", "aria-label": "Recovery codes", children: [
|
|
4895
4960
|
codes.map((code, i) => /* @__PURE__ */ jsxs20("li", { className: "flex min-h-7 items-center gap-1", children: [
|
|
4896
4961
|
/* @__PURE__ */ jsx21("code", { className: "min-w-0 flex-1 break-all font-mono text-sm text-foreground", children: code }),
|
|
4897
|
-
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CopyGlyph, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void
|
|
4962
|
+
/* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CopyGlyph, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue2(code, "Recovery code") }),
|
|
4898
4963
|
canEdit ? /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CheckGlyph, {}), disabled: busy, onClick: () => void markUsed(i), children: "Mark used" }) : null
|
|
4899
4964
|
] }, `${i}-${code}`)),
|
|
4900
4965
|
error ? /* @__PURE__ */ jsx21("li", { role: "alert", className: "text-xs text-destructive", children: error }) : null
|
|
@@ -5086,7 +5151,7 @@ var MEMBER_ACCESS_LABEL = { none: "No access", use: "Can use", editor: "Can edit
|
|
|
5086
5151
|
function levelOf(flags) {
|
|
5087
5152
|
return flags.can_manage ? "edit" : "use";
|
|
5088
5153
|
}
|
|
5089
|
-
function
|
|
5154
|
+
function shareFlagsOf(level) {
|
|
5090
5155
|
return { can_use: true, can_manage: level === "edit" };
|
|
5091
5156
|
}
|
|
5092
5157
|
function isEmail(value) {
|
|
@@ -5500,6 +5565,7 @@ function SharingSummary({ item, port, className }) {
|
|
|
5500
5565
|
}
|
|
5501
5566
|
|
|
5502
5567
|
// src/ItemPane.tsx
|
|
5568
|
+
import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
|
|
5503
5569
|
import { Fragment as Fragment15, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5504
5570
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5505
5571
|
function ItemPane(props) {
|
|
@@ -5647,7 +5713,7 @@ function ItemPane(props) {
|
|
|
5647
5713
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5648
5714
|
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: [
|
|
5649
5715
|
onBack ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(ChevronLeftGlyph, {}), "aria-label": "Back", onClick: mode === "new" ? onCancelNew : onBack }) : null,
|
|
5650
|
-
/* @__PURE__ */ jsx26(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ?
|
|
5716
|
+
/* @__PURE__ */ jsx26(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? loginSiteOf(item) : loginSiteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
|
|
5651
5717
|
/* @__PURE__ */ jsxs24("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
5652
5718
|
/* @__PURE__ */ jsx26("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
|
|
5653
5719
|
/* @__PURE__ */ jsxs24("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
@@ -5880,9 +5946,9 @@ function ItemPane(props) {
|
|
|
5880
5946
|
filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: false }) : null,
|
|
5881
5947
|
/* @__PURE__ */ jsxs24("p", { className: cn12("px-1 text-xs text-muted-foreground"), children: [
|
|
5882
5948
|
"Modified ",
|
|
5883
|
-
|
|
5949
|
+
formatAbsoluteDate3(item.updatedAt, DAY_FORMAT, ""),
|
|
5884
5950
|
" \xB7 Created ",
|
|
5885
|
-
|
|
5951
|
+
formatAbsoluteDate3(item.createdAt, DAY_FORMAT, "")
|
|
5886
5952
|
] })
|
|
5887
5953
|
] }) : null }) })
|
|
5888
5954
|
] }) });
|
|
@@ -5897,7 +5963,7 @@ var SORTS2 = [
|
|
|
5897
5963
|
{ value: "created", label: "Recently added" }
|
|
5898
5964
|
];
|
|
5899
5965
|
function subtitleOf(item, withOwner) {
|
|
5900
|
-
const what =
|
|
5966
|
+
const what = loginSiteOf(item) || item.definitionLabel;
|
|
5901
5967
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
5902
5968
|
}
|
|
5903
5969
|
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header }) {
|
|
@@ -5963,7 +6029,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
5963
6029
|
setBusy(true);
|
|
5964
6030
|
try {
|
|
5965
6031
|
const v = await confirmed(() => port.reveal(item, key));
|
|
5966
|
-
await copy(v, label);
|
|
6032
|
+
await copy(v, label, { secret: key !== user?.key || user.handling !== "visible" });
|
|
5967
6033
|
} catch (e) {
|
|
5968
6034
|
if (!wasCancelled(e)) notify(e instanceof Error ? e.message : `${label} could not be read`, "error");
|
|
5969
6035
|
} finally {
|
|
@@ -5980,7 +6046,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
5980
6046
|
onClick: () => onSelect(item.id),
|
|
5981
6047
|
className: cn13("flex h-12 w-full items-center gap-3 rounded-lg px-2 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
|
|
5982
6048
|
children: [
|
|
5983
|
-
/* @__PURE__ */ jsx27(ItemIcon, { definitionKey: item.definitionKey, family, site:
|
|
6049
|
+
/* @__PURE__ */ jsx27(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
|
|
5984
6050
|
/* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
5985
6051
|
/* @__PURE__ */ jsx27("span", { className: "truncate text-sm font-medium", children: item.name }),
|
|
5986
6052
|
/* @__PURE__ */ jsx27("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
|
|
@@ -5998,6 +6064,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
5998
6064
|
// src/lists/TrashView.tsx
|
|
5999
6065
|
import { useState as useState29 } from "react";
|
|
6000
6066
|
import { Button as Button24 } from "@ai-matrx/design-system/controls";
|
|
6067
|
+
import { formatAbsoluteDate as formatAbsoluteDate4 } from "@ai-matrx/kit/format";
|
|
6001
6068
|
|
|
6002
6069
|
// src/lists/logic.ts
|
|
6003
6070
|
var ENTITY_TYPE = "credential_item";
|
|
@@ -6008,7 +6075,7 @@ function favoriteIds(data) {
|
|
|
6008
6075
|
function recentIds(data, limit = 50) {
|
|
6009
6076
|
return rowsOf(data).filter((r) => typeof r.last_viewed_at === "string" && r.last_viewed_at !== "").sort((a, b) => Date.parse(b.last_viewed_at) - Date.parse(a.last_viewed_at)).slice(0, limit).map((r) => r.entity_id);
|
|
6010
6077
|
}
|
|
6011
|
-
function
|
|
6078
|
+
function trashItemMatchesQuery(item, query) {
|
|
6012
6079
|
const q = query.trim().toLowerCase();
|
|
6013
6080
|
if (!q) return true;
|
|
6014
6081
|
return [item.name, item.definitionLabel, item.owner.label, ...item.tags].some((s) => s.toLowerCase().includes(q));
|
|
@@ -6140,7 +6207,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6140
6207
|
const confirmed = useConfirmed();
|
|
6141
6208
|
const [busyId, setBusyId] = useState29(null);
|
|
6142
6209
|
const [message2, setMessage] = useState29(null);
|
|
6143
|
-
const shown = deleted.filter((i) =>
|
|
6210
|
+
const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
|
|
6144
6211
|
const [restoring, setRestoring] = useState29(null);
|
|
6145
6212
|
const restore = async (item, deletionId) => {
|
|
6146
6213
|
setBusyId(item.id);
|
|
@@ -6165,7 +6232,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6165
6232
|
/* @__PURE__ */ jsxs27("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
|
|
6166
6233
|
/* @__PURE__ */ jsxs27("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6167
6234
|
/* @__PURE__ */ jsx29("span", { className: "truncate text-sm text-foreground", children: item.name }),
|
|
6168
|
-
/* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: [item.deletion?.deletedAt ? `Deleted ${
|
|
6235
|
+
/* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: [item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null, item.owner.kind !== "me" ? item.owner.label : null].filter(Boolean).join(" \xB7 ") })
|
|
6169
6236
|
] }),
|
|
6170
6237
|
/* @__PURE__ */ jsx29(Button24, { variant: "outline", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6171
6238
|
] }, item.id)
|
|
@@ -6252,6 +6319,7 @@ import { useEffect as useEffect19, useRef as useRef16, useState as useState31 }
|
|
|
6252
6319
|
import { confirm as confirm10 } from "@ai-matrx/kit/confirm-opener";
|
|
6253
6320
|
import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
|
|
6254
6321
|
import { Badge as Badge8, Button as Button26, Field as Field11, RegionSkeleton as RegionSkeleton2, SegmentedControl as SegmentedControl5, Textarea as Textarea4 } from "@ai-matrx/design-system/controls";
|
|
6322
|
+
import { formatAbsoluteDate as formatAbsoluteDate5 } from "@ai-matrx/kit/format";
|
|
6255
6323
|
|
|
6256
6324
|
// src/sharing/secure-link-logic.ts
|
|
6257
6325
|
import { formatDurationMinutes } from "@ai-matrx/kit/format";
|
|
@@ -6521,7 +6589,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6521
6589
|
);
|
|
6522
6590
|
}
|
|
6523
6591
|
function sentMeta(row, options) {
|
|
6524
|
-
const when = row.status === "pending" ? `Until ${
|
|
6592
|
+
const when = row.status === "pending" ? `Until ${formatAbsoluteDate5(row.expiresAt, void 0, "")}` : row.status === "viewed" && row.viewedAt ? formatAbsoluteDate5(row.viewedAt, void 0, "") : formatAbsoluteDate5(row.createdAt, DAY_FORMAT, "");
|
|
6525
6593
|
const carried = row.fieldKeys.length ? carriedWords(row.fieldKeys, options?.fields ?? []) : "";
|
|
6526
6594
|
return [when, carried].filter(Boolean).join(" \xB7 ");
|
|
6527
6595
|
}
|
|
@@ -6530,6 +6598,7 @@ function sentMeta(row, options) {
|
|
|
6530
6598
|
import { useCallback as useCallback4, useEffect as useEffect20, useState as useState32 } from "react";
|
|
6531
6599
|
import { confirm as confirm11 } from "@ai-matrx/kit/confirm-opener";
|
|
6532
6600
|
import { Button as Button27, RegionSkeleton as RegionSkeleton3 } from "@ai-matrx/design-system/controls";
|
|
6601
|
+
import { formatAbsoluteDate as formatAbsoluteDate6 } from "@ai-matrx/kit/format";
|
|
6533
6602
|
|
|
6534
6603
|
// src/devices/logic.ts
|
|
6535
6604
|
var PASSKEY_RP_ID = "aimatrx.com";
|
|
@@ -6659,13 +6728,13 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6659
6728
|
Row,
|
|
6660
6729
|
{
|
|
6661
6730
|
label: off ? "Turned off" : "Can fill",
|
|
6662
|
-
hint: off ?
|
|
6731
|
+
hint: off ? formatAbsoluteDate6(device.revokedAt, DAY_FORMAT, "") : void 0,
|
|
6663
6732
|
actions: off ? null : /* @__PURE__ */ jsx32(Button27, { variant: "outline", icon: /* @__PURE__ */ jsx32(PowerGlyph, {}), disabled: busyId !== null, onClick: () => void revoke(device), children: "Revoke" }),
|
|
6664
6733
|
children: /* @__PURE__ */ jsxs30("span", { className: "flex min-w-0 flex-col", children: [
|
|
6665
6734
|
/* @__PURE__ */ jsx32("span", { className: off ? "truncate text-muted-foreground" : "truncate text-foreground", children: device.label }),
|
|
6666
6735
|
/* @__PURE__ */ jsxs30("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6667
|
-
device.lastUsedAt ? `Last used ${
|
|
6668
|
-
device.addedAt ? ` \xB7 added ${
|
|
6736
|
+
device.lastUsedAt ? `Last used ${formatAbsoluteDate6(device.lastUsedAt, void 0, "")}` : "Never used",
|
|
6737
|
+
device.addedAt ? ` \xB7 added ${formatAbsoluteDate6(device.addedAt, DAY_FORMAT, "")}` : ""
|
|
6669
6738
|
] })
|
|
6670
6739
|
] })
|
|
6671
6740
|
},
|
|
@@ -6759,7 +6828,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6759
6828
|
"Return to ",
|
|
6760
6829
|
where,
|
|
6761
6830
|
" by ",
|
|
6762
|
-
|
|
6831
|
+
formatAbsoluteDate6(approvedUntil, void 0, ""),
|
|
6763
6832
|
"."
|
|
6764
6833
|
] }) }) : !passkeys ? /* @__PURE__ */ jsxs30(Empty, { children: [
|
|
6765
6834
|
"Approve with your password in ",
|
|
@@ -7137,12 +7206,12 @@ import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuConte
|
|
|
7137
7206
|
import { Button as Button32 } from "@ai-matrx/design-system/controls";
|
|
7138
7207
|
|
|
7139
7208
|
// src/extension/CaptureCard.tsx
|
|
7140
|
-
import { useState as useState35, useSyncExternalStore as
|
|
7209
|
+
import { useState as useState35, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
7141
7210
|
import { Button as Button29, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
|
|
7142
7211
|
import { Fragment as Fragment19, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7143
7212
|
var SEARCH_FROM = 4;
|
|
7144
7213
|
function CaptureCard({ capture, onChanged }) {
|
|
7145
|
-
const prompt =
|
|
7214
|
+
const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
|
|
7146
7215
|
const notify = useNotify();
|
|
7147
7216
|
const [busy, setBusy] = useState35(false);
|
|
7148
7217
|
const [q, setQ] = useState35("");
|
|
@@ -7201,12 +7270,12 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7201
7270
|
}
|
|
7202
7271
|
|
|
7203
7272
|
// src/extension/FillSetupCard.tsx
|
|
7204
|
-
import { useRef as useRef18, useState as useState36, useSyncExternalStore as
|
|
7273
|
+
import { useRef as useRef18, useState as useState36, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
7205
7274
|
import { Button as Button30, Field as Field12 } from "@ai-matrx/design-system/controls";
|
|
7206
7275
|
import { jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
7207
7276
|
function FillSetupCard({ fillSetup }) {
|
|
7208
7277
|
const notify = useNotify();
|
|
7209
|
-
const state =
|
|
7278
|
+
const state = useSyncExternalStore4(fillSetup.subscribe, fillSetup.get, fillSetup.get);
|
|
7210
7279
|
const box = useRef18(null);
|
|
7211
7280
|
const [busy, setBusy] = useState36(false);
|
|
7212
7281
|
const [error, setError] = useState36(null);
|
|
@@ -7450,10 +7519,10 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7450
7519
|
setReading(false);
|
|
7451
7520
|
}
|
|
7452
7521
|
};
|
|
7453
|
-
const subtitle = [item ?
|
|
7522
|
+
const subtitle = [item ? loginSiteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
|
|
7454
7523
|
return /* @__PURE__ */ jsxs35("li", { className: "flex h-12 items-center gap-1 pl-1 pr-2", "data-item": itemId, children: [
|
|
7455
7524
|
/* @__PURE__ */ jsxs35("button", { type: "button", onClick: () => onOpen(itemId), className: "flex h-11 min-w-0 flex-1 items-center gap-3 rounded-lg px-2 text-left hover:bg-accent", children: [
|
|
7456
|
-
/* @__PURE__ */ jsx37(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ?
|
|
7525
|
+
/* @__PURE__ */ jsx37(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? loginSiteOf(item) : "" }),
|
|
7457
7526
|
/* @__PURE__ */ jsxs35("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
7458
7527
|
/* @__PURE__ */ jsx37("span", { className: "truncate text-sm font-medium", children: item?.name ?? "Saved login" }),
|
|
7459
7528
|
subtitle ? /* @__PURE__ */ jsx37("span", { className: "truncate text-xs text-muted-foreground", children: subtitle }) : null
|
|
@@ -7641,7 +7710,31 @@ function ImportWithLimits(props) {
|
|
|
7641
7710
|
return /* @__PURE__ */ jsx39(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ jsx39(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
|
|
7642
7711
|
}
|
|
7643
7712
|
function VaultApp(props) {
|
|
7644
|
-
|
|
7713
|
+
const lock = props.host?.lock;
|
|
7714
|
+
const locked = useLocked(lock);
|
|
7715
|
+
const port = useMemo6(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
7716
|
+
return /* @__PURE__ */ jsx39("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ jsx39(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ jsx39(LockedScreen, { lock }) : /* @__PURE__ */ jsx39(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ jsx39(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ jsx39(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ jsx39(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ jsx39(Workspace, { ...props, port }) }) }) }) }) }) });
|
|
7717
|
+
}
|
|
7718
|
+
function LockedScreen({ lock }) {
|
|
7719
|
+
const [busy, setBusy] = useState40(false);
|
|
7720
|
+
const [error, setError] = useState40(null);
|
|
7721
|
+
const unlock = async () => {
|
|
7722
|
+
setBusy(true);
|
|
7723
|
+
setError(null);
|
|
7724
|
+
try {
|
|
7725
|
+
await lock.unlock();
|
|
7726
|
+
} catch (e) {
|
|
7727
|
+
setError(e instanceof Error && e.message ? e.message : "The vault stayed locked.");
|
|
7728
|
+
} finally {
|
|
7729
|
+
setBusy(false);
|
|
7730
|
+
}
|
|
7731
|
+
};
|
|
7732
|
+
return /* @__PURE__ */ jsxs37("div", { role: "region", "aria-label": "Vault locked", className: "flex h-full min-h-0 flex-col items-center justify-center gap-3 p-6 text-center", children: [
|
|
7733
|
+
/* @__PURE__ */ jsx39(LockGlyph, { className: "size-8 text-muted-foreground" }),
|
|
7734
|
+
/* @__PURE__ */ jsx39("div", { className: "text-base font-medium text-foreground", children: "Vault locked" }),
|
|
7735
|
+
/* @__PURE__ */ jsx39(Button33, { variant: "primary", disabled: busy, onClick: () => void unlock(), children: lock.unlockLabel ?? "Unlock" }),
|
|
7736
|
+
error ? /* @__PURE__ */ jsx39("div", { role: "alert", className: "max-w-sm text-sm text-destructive", children: error }) : null
|
|
7737
|
+
] });
|
|
7645
7738
|
}
|
|
7646
7739
|
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange }) {
|
|
7647
7740
|
const rootRef = useRef19(null);
|
|
@@ -7794,6 +7887,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7794
7887
|
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: host.nativeProvider.openSetup, children: [
|
|
7795
7888
|
/* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4" }),
|
|
7796
7889
|
"System AutoFill"
|
|
7890
|
+
] }) : null,
|
|
7891
|
+
host.lock?.lock ? /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
7892
|
+
/* @__PURE__ */ jsx39(LockGlyph, { className: "size-4" }),
|
|
7893
|
+
"Lock"
|
|
7797
7894
|
] }) : null
|
|
7798
7895
|
] })
|
|
7799
7896
|
] })
|
|
@@ -8408,7 +8505,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
8408
8505
|
return r.grants.map(grantOf);
|
|
8409
8506
|
},
|
|
8410
8507
|
async addPerson(item, email, level) {
|
|
8411
|
-
const w = await account6.addGrant(api, { path: { item_id: item.id }, body: { recipient_email: email.trim(), ...
|
|
8508
|
+
const w = await account6.addGrant(api, { path: { item_id: item.id }, body: { recipient_email: email.trim(), ...shareFlagsOf(level), initiation: "user" } }, ctx.optsFor(item));
|
|
8412
8509
|
return grantOf(w);
|
|
8413
8510
|
},
|
|
8414
8511
|
async addOrganization(item, organizationId, level) {
|
|
@@ -8416,14 +8513,14 @@ function createSharingPort(ctx, options = {}) {
|
|
|
8416
8513
|
return grantOf(w);
|
|
8417
8514
|
},
|
|
8418
8515
|
async setLevel(item, grant, level) {
|
|
8419
|
-
const w = await account6.updateGrant(api, { path: { item_id: item.id, grant_id: grant.id }, body: { ...
|
|
8516
|
+
const w = await account6.updateGrant(api, { path: { item_id: item.id, grant_id: grant.id }, body: { ...shareFlagsOf(level), initiation: "user" } }, ctx.optsFor(item));
|
|
8420
8517
|
return grantOf(w);
|
|
8421
8518
|
},
|
|
8422
8519
|
async revoke(item, grant) {
|
|
8423
8520
|
await account6.removeGrant(api, { path: { item_id: item.id, grant_id: grant.id } }, ctx.optsFor(item));
|
|
8424
8521
|
},
|
|
8425
8522
|
async setAccessMode(item, mode, people) {
|
|
8426
|
-
const grantees = mode === "restricted" ? people.filter((g) => g.kind === "person" && g.userId).map((g) => ({ user_id: g.userId, ...
|
|
8523
|
+
const grantees = mode === "restricted" ? people.filter((g) => g.kind === "person" && g.userId).map((g) => ({ user_id: g.userId, ...shareFlagsOf(g.level) })) : [];
|
|
8427
8524
|
await account6.share(api, { path: { item_id: item.id }, body: { access_mode: mode, grantees, initiation: "user" } }, ctx.optsFor(item));
|
|
8428
8525
|
return ctx.refetch(item.id, item.owner);
|
|
8429
8526
|
},
|
|
@@ -8826,18 +8923,22 @@ export {
|
|
|
8826
8923
|
CATEGORIES,
|
|
8827
8924
|
DEFAULT_LOCATION,
|
|
8828
8925
|
GenerateButton,
|
|
8926
|
+
LOCKED_MESSAGE,
|
|
8829
8927
|
VaultApp,
|
|
8928
|
+
VaultLockedError,
|
|
8830
8929
|
categoryOf,
|
|
8930
|
+
copyValue,
|
|
8831
8931
|
createApiVaultPort,
|
|
8832
8932
|
createSupabaseIdentity,
|
|
8833
8933
|
createVaultKnobs,
|
|
8934
|
+
guardPort,
|
|
8834
8935
|
inferFromUrl,
|
|
8835
8936
|
locationFromParams,
|
|
8836
8937
|
locationToParams,
|
|
8938
|
+
loginSiteOf,
|
|
8837
8939
|
matchesQuery,
|
|
8838
8940
|
needsRecentSignIn,
|
|
8839
8941
|
parseDefinitions,
|
|
8840
|
-
siteOf,
|
|
8841
8942
|
sortItems
|
|
8842
8943
|
};
|
|
8843
8944
|
//# sourceMappingURL=index.js.map
|