@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/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
- return useCallback((text, label) => copyText(text, { successMessage: `${label} copied`, failureMessage: `${label} could not be copied`, notify: (m, k) => notify(m, k === "error" ? "error" : "success") }), [notify]);
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
- function useTransientSecret(ms = 2e4) {
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 createContext3, useContext as useContext3, useEffect as useEffect4, useState as useState4 } from "react";
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 = createContext3(false);
539
- var Room = createContext3(null);
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 = useContext3(InPanel);
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 = useContext3(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
- function formatDate(iso, withTime = false) {
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 copyValue = useCopy();
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 copyValue(v, field.label);
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 copyValue = useCopy();
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 copyValue(value, typeof label === "string" && label ? label : "Value") })
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 siteOf(item) {
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 = siteOf(a), y = siteOf(b);
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: formatDate(entry.at, true), children: [
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
- formatDate(page.captureStartedAt, true)
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 copyValue = useCopy();
1356
+ const copyValue2 = useCopy();
1331
1357
  const [busy, setBusy] = useState7(false);
1332
- const when = formatDate(entry.recordedAt, true);
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 copyValue(v, `Earlier ${label.toLowerCase()}`);
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, siteOf2) {
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 = siteOf2(c).toLowerCase();
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 copyValue = useCopy();
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 copyValue(code, "One-time code");
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, siteOf);
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: siteOf(c) ? `${c.name} \xB7 ${siteOf(c)}` : c.name }))],
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, siteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
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 createContext4, useContext as useContext4, useEffect as useEffect12, useRef as useRef10, useState as useState15 } from "react";
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 = createContext4(null);
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 useContext4(LimitsCtx);
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 copyValue = useCopy();
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 copyValue(candidate.value, "Generated password");
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 copyValue = useCopy();
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 copyValue(code, "Recovery code") }),
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 flagsOf(level) {
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 ? siteOf(item) : siteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
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
- formatDate(item.updatedAt),
5949
+ formatAbsoluteDate3(item.updatedAt, DAY_FORMAT, ""),
5884
5950
  " \xB7 Created ",
5885
- formatDate(item.createdAt)
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 = siteOf(item) || item.definitionLabel;
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: siteOf(item), inverted: on }),
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 matchesQuery2(item, query) {
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) => matchesQuery2(i, query));
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 ${formatDate(item.deletion.deletedAt)}` : null, item.owner.kind !== "me" ? item.owner.label : null].filter(Boolean).join(" \xB7 ") })
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 ${formatDate(row.expiresAt, true)}` : row.status === "viewed" && row.viewedAt ? formatDate(row.viewedAt, true) : formatDate(row.createdAt);
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 ? formatDate(device.revokedAt) : void 0,
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 ${formatDate(device.lastUsedAt, true)}` : "Never used",
6668
- device.addedAt ? ` \xB7 added ${formatDate(device.addedAt)}` : ""
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
- formatDate(approvedUntil, true),
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 useSyncExternalStore2 } from "react";
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 = useSyncExternalStore2(capture.subscribe, capture.get, capture.get);
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 useSyncExternalStore3 } from "react";
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 = useSyncExternalStore3(fillSetup.subscribe, fillSetup.get, fillSetup.get);
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 ? siteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
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 ? siteOf(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
- return /* @__PURE__ */ jsx39("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ jsx39(NoticeProvider, { notify: props.notify, children: /* @__PURE__ */ jsx39(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ jsx39(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ jsx39(Workspace, { ...props }) }) }) }) });
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(), ...flagsOf(level), initiation: "user" } }, ctx.optsFor(item));
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: { ...flagsOf(level), initiation: "user" } }, ctx.optsFor(item));
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, ...flagsOf(g.level) })) : [];
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