@ai-matrx/vault 0.1.5 → 0.1.6

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.cjs CHANGED
@@ -138,11 +138,15 @@ __export(src_exports, {
138
138
  CATEGORIES: () => CATEGORIES,
139
139
  DEFAULT_LOCATION: () => DEFAULT_LOCATION,
140
140
  GenerateButton: () => GenerateButton,
141
+ LOCKED_MESSAGE: () => LOCKED_MESSAGE,
141
142
  VaultApp: () => VaultApp,
143
+ VaultLockedError: () => VaultLockedError,
142
144
  categoryOf: () => categoryOf,
145
+ copyValue: () => copyValue,
143
146
  createApiVaultPort: () => createApiVaultPort,
144
147
  createSupabaseIdentity: () => createSupabaseIdentity,
145
148
  createVaultKnobs: () => createVaultKnobs,
149
+ guardPort: () => guardPort,
146
150
  inferFromUrl: () => inferFromUrl,
147
151
  locationFromParams: () => locationFromParams,
148
152
  locationToParams: () => locationToParams,
@@ -155,7 +159,7 @@ __export(src_exports, {
155
159
  module.exports = __toCommonJS(src_exports);
156
160
 
157
161
  // src/VaultApp.tsx
158
- var import_react40 = require("react");
162
+ var import_react41 = require("react");
159
163
  var import_design_system25 = require("@ai-matrx/design-system");
160
164
  var import_controls34 = require("@ai-matrx/design-system/controls");
161
165
  var import_confirm_opener13 = require("@ai-matrx/kit/confirm-opener");
@@ -169,9 +173,28 @@ var Ctx = (0, import_react.createContext)(() => void 0);
169
173
  function useNotify() {
170
174
  return (0, import_react.useContext)(Ctx);
171
175
  }
176
+ async function copyValue(text, label, options, deps) {
177
+ const secret = options.secret ?? true;
178
+ if (deps.clipboard) {
179
+ try {
180
+ await deps.clipboard.copy(text, { secret });
181
+ deps.notify(`${label} copied`, "success");
182
+ return true;
183
+ } catch (e) {
184
+ deps.notify(e instanceof Error && e.message ? e.message : `${label} could not be copied`, "error");
185
+ return false;
186
+ }
187
+ }
188
+ return (0, import_clipboard.copyText)(text, { successMessage: `${label} copied`, failureMessage: `${label} could not be copied`, notify: (m, k) => deps.notify(m, k === "error" ? "error" : "success") });
189
+ }
190
+ var ClipboardCtx = (0, import_react.createContext)(void 0);
191
+ function ClipboardProvider({ clipboard, children }) {
192
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClipboardCtx.Provider, { value: clipboard, children });
193
+ }
172
194
  function useCopy() {
173
195
  const notify = useNotify();
174
- return (0, import_react.useCallback)((text, label) => (0, import_clipboard.copyText)(text, { successMessage: `${label} copied`, failureMessage: `${label} could not be copied`, notify: (m, k) => notify(m, k === "error" ? "error" : "success") }), [notify]);
196
+ const clipboard = (0, import_react.useContext)(ClipboardCtx);
197
+ return (0, import_react.useCallback)((text, label, options = {}) => copyValue(text, label, options, { clipboard, notify }), [notify, clipboard]);
175
198
  }
176
199
  function NoticeProvider({ notify, children }) {
177
200
  const [shown, setShown] = (0, import_react.useState)(null);
@@ -549,7 +572,15 @@ var import_design_system5 = require("@ai-matrx/design-system");
549
572
 
550
573
  // src/hooks.ts
551
574
  var import_react3 = require("react");
552
- function useTransientSecret(ms = 2e4) {
575
+ var DEFAULT_REVEAL_MS = 2e4;
576
+ var RevealMs = (0, import_react3.createContext)(DEFAULT_REVEAL_MS);
577
+ function RevealSecondsProvider({ seconds, children }) {
578
+ const ms = seconds !== void 0 && Number.isFinite(seconds) && seconds > 0 ? seconds * 1e3 : DEFAULT_REVEAL_MS;
579
+ return (0, import_react3.createElement)(RevealMs.Provider, { value: ms }, children);
580
+ }
581
+ function useTransientSecret(given) {
582
+ const fromHost = (0, import_react3.useContext)(RevealMs);
583
+ const ms = given ?? fromHost;
553
584
  const [value, setValue] = (0, import_react3.useState)(null);
554
585
  const timer2 = (0, import_react3.useRef)(null);
555
586
  const clear = (0, import_react3.useCallback)(() => {
@@ -664,7 +695,7 @@ function SecretText({ value, multiline }) {
664
695
  var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
665
696
  function SecretRow({ port, item, field, extra }) {
666
697
  const confirmed = useConfirmed();
667
- const copyValue = useCopy();
698
+ const copyValue2 = useCopy();
668
699
  const secret = useTransientSecret();
669
700
  const [plain, setPlain] = (0, import_react5.useState)(null);
670
701
  const [busy, setBusy] = (0, import_react5.useState)(false);
@@ -705,7 +736,7 @@ function SecretRow({ port, item, field, extra }) {
705
736
  }
706
737
  async function copy() {
707
738
  const v = await fetchValue();
708
- if (v !== null) await copyValue(v, field.label);
739
+ if (v !== null) await copyValue2(v, field.label, { secret: !visible });
709
740
  }
710
741
  const multiline = field.kind === "multiline";
711
742
  const shown = visible ? plain : secret.value;
@@ -724,7 +755,7 @@ function SecretRow({ port, item, field, extra }) {
724
755
  );
725
756
  }
726
757
  function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
727
- const copyValue = useCopy();
758
+ const copyValue2 = useCopy();
728
759
  const isUrl = /^https?:\/\//i.test(value);
729
760
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
730
761
  Row,
@@ -735,7 +766,7 @@ function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
735
766
  actions: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
736
767
  extra,
737
768
  isUrl && openUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExternalGlyph, {}), "aria-label": `Open ${value}`, onClick: () => openUrl(value) }) : null,
738
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CopyGlyph, {}), "aria-label": `Copy ${typeof label === "string" ? label : "value"}`, onClick: () => void copyValue(value, typeof label === "string" && label ? label : "Value") })
769
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CopyGlyph, {}), "aria-label": `Copy ${typeof label === "string" ? label : "value"}`, onClick: () => void copyValue2(value, typeof label === "string" && label ? label : "Value", { secret: false }) })
739
770
  ] }),
740
771
  children: isUrl && openUrl ? (
741
772
  // A real link (right-click, copy link address, open in a new tab); a click goes through the host's opener.
@@ -1381,7 +1412,7 @@ function HistoryPanel({ item, port, arg, onClose, onChanged }) {
1381
1412
  function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, onError }) {
1382
1413
  const confirmed = useConfirmed();
1383
1414
  const secret = useTransientSecret();
1384
- const copyValue = useCopy();
1415
+ const copyValue2 = useCopy();
1385
1416
  const [busy, setBusy] = (0, import_react7.useState)(false);
1386
1417
  const when = formatDate(entry.recordedAt, true);
1387
1418
  async function read() {
@@ -1404,7 +1435,7 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
1404
1435
  }
1405
1436
  async function copy() {
1406
1437
  const v = await read();
1407
- if (v !== null) await copyValue(v, `Earlier ${label.toLowerCase()}`);
1438
+ if (v !== null) await copyValue2(v, `Earlier ${label.toLowerCase()}`);
1408
1439
  }
1409
1440
  async function restore() {
1410
1441
  const yes = await (0, import_confirm_opener.confirm)({
@@ -1589,13 +1620,13 @@ function CountdownRing({ remaining, period, loading = false, className }) {
1589
1620
  }
1590
1621
  function useCopied() {
1591
1622
  const [copied, setCopied] = (0, import_react8.useState)(false);
1592
- const copyValue = useCopy();
1623
+ const copyValue2 = useCopy();
1593
1624
  const t = (0, import_react8.useRef)(null);
1594
1625
  (0, import_react8.useEffect)(() => () => void (t.current && clearTimeout(t.current)), []);
1595
1626
  return {
1596
1627
  copied,
1597
1628
  copy: async (code) => {
1598
- const ok = await copyValue(code, "One-time code");
1629
+ const ok = await copyValue2(code, "One-time code");
1599
1630
  if (!ok) return;
1600
1631
  setCopied(true);
1601
1632
  if (t.current) clearTimeout(t.current);
@@ -2810,7 +2841,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2810
2841
  const [candidate, setCandidate] = (0, import_react15.useState)(null);
2811
2842
  const [revealed, setRevealed] = (0, import_react15.useState)(false);
2812
2843
  const [note, setNote] = (0, import_react15.useState)(null);
2813
- const copyValue = useCopy();
2844
+ const copyValue2 = useCopy();
2814
2845
  const expiry = (0, import_react15.useRef)(null);
2815
2846
  const drop = () => {
2816
2847
  if (expiry.current) clearTimeout(expiry.current);
@@ -2870,7 +2901,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2870
2901
  const strength = candidate ? strengthOf(candidate.bits) : null;
2871
2902
  const copy = async () => {
2872
2903
  if (!candidate) return;
2873
- const ok = await copyValue(candidate.value, "Generated password");
2904
+ const ok = await copyValue2(candidate.value, "Generated password");
2874
2905
  setNote(ok ? { tone: "success", text: "Copied. Your clipboard keeps it." } : { tone: "destructive", text: "Couldn\u2019t copy. Reveal it and copy by hand." });
2875
2906
  };
2876
2907
  const use = () => {
@@ -2981,8 +3012,47 @@ function importLimitsFrom(resolved) {
2981
3012
  return out;
2982
3013
  }
2983
3014
 
3015
+ // src/lock.ts
3016
+ var import_react16 = require("react");
3017
+ var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
3018
+ var VaultLockedError = class extends Error {
3019
+ code = "vault_locked";
3020
+ constructor() {
3021
+ super(LOCKED_MESSAGE);
3022
+ this.name = "VaultLockedError";
3023
+ }
3024
+ };
3025
+ function guardPort(port, locked) {
3026
+ const cache = /* @__PURE__ */ new WeakMap();
3027
+ const wrap = (target) => {
3028
+ const hit = cache.get(target);
3029
+ if (hit) return hit;
3030
+ const proxy = new Proxy(target, {
3031
+ get(obj2, key, receiver) {
3032
+ const value = Reflect.get(obj2, key, receiver);
3033
+ if (typeof value === "function") {
3034
+ return (...args) => {
3035
+ if (locked()) return Promise.reject(new VaultLockedError());
3036
+ return value.apply(obj2, args);
3037
+ };
3038
+ }
3039
+ if (value && typeof value === "object") return wrap(value);
3040
+ return value;
3041
+ }
3042
+ });
3043
+ cache.set(target, proxy);
3044
+ return proxy;
3045
+ };
3046
+ return wrap(port);
3047
+ }
3048
+ var NEVER = () => () => void 0;
3049
+ var UNLOCKED = () => false;
3050
+ function useLocked(lock) {
3051
+ return (0, import_react16.useSyncExternalStore)(lock ? lock.subscribe : NEVER, lock ? () => lock.locked() : UNLOCKED, UNLOCKED);
3052
+ }
3053
+
2984
3054
  // src/io/BackupPanel.tsx
2985
- var import_react17 = require("react");
3055
+ var import_react18 = require("react");
2986
3056
  var import_controls13 = require("@ai-matrx/design-system/controls");
2987
3057
  var import_download = require("@ai-matrx/kit/download");
2988
3058
  var import_confirm_opener4 = require("@ai-matrx/kit/confirm-opener");
@@ -3075,7 +3145,7 @@ function startNewRestoreRun(preview) {
3075
3145
  }
3076
3146
 
3077
3147
  // src/io/lines.tsx
3078
- var import_react16 = require("react");
3148
+ var import_react17 = require("react");
3079
3149
  var import_design_system11 = require("@ai-matrx/design-system");
3080
3150
  var import_controls12 = require("@ai-matrx/design-system/controls");
3081
3151
  var import_jsx_runtime15 = require("react/jsx-runtime");
@@ -3088,7 +3158,7 @@ function PickLine({ checked, onChange, disabled = false, title, detail, badge, t
3088
3158
  ] });
3089
3159
  }
3090
3160
  function Windowed({ items, size = 150, render }) {
3091
- const [all, setAll] = (0, import_react16.useState)(false);
3161
+ const [all, setAll] = (0, import_react17.useState)(false);
3092
3162
  const shown = all ? items : items.slice(0, size);
3093
3163
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3094
3164
  shown.map(render),
@@ -3099,7 +3169,7 @@ function Windowed({ items, size = 150, render }) {
3099
3169
  ] });
3100
3170
  }
3101
3171
  function More({ title = "More", children }) {
3102
- const [open, setOpen] = (0, import_react16.useState)(false);
3172
+ const [open, setOpen] = (0, import_react17.useState)(false);
3103
3173
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-2", children: [
3104
3174
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls12.DisclosureHeader, { open, title, onClick: () => setOpen((o) => !o) }),
3105
3175
  open ? children : null
@@ -3138,21 +3208,21 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
3138
3208
  }
3139
3209
  function BackupPanel({ port, items, onClose, onChanged }) {
3140
3210
  const confirmed = useConfirmed();
3141
- const fileInput = (0, import_react17.useRef)(null);
3142
- const abort = (0, import_react17.useRef)(null);
3143
- const [mode, setMode] = (0, import_react17.useState)("backup");
3144
- const [busy, setBusy] = (0, import_react17.useState)(false);
3145
- const [error, setError] = (0, import_react17.useState)(null);
3146
- const [passphrase, setPassphrase] = (0, import_react17.useState)("");
3147
- const [repeat, setRepeat] = (0, import_react17.useState)("");
3148
- const [accepted, setAccepted] = (0, import_react17.useState)(false);
3149
- const [selected, setSelected] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
3150
- const [backup, setBackup] = (0, import_react17.useState)(null);
3151
- const [file, setFile] = (0, import_react17.useState)(null);
3152
- const [restorePreview, setRestorePreview] = (0, import_react17.useState)(null);
3153
- const [runId, setRunId] = (0, import_react17.useState)(null);
3154
- const [result, setResult] = (0, import_react17.useState)(null);
3155
- (0, import_react17.useEffect)(() => () => abort.current?.abort(), []);
3211
+ const fileInput = (0, import_react18.useRef)(null);
3212
+ const abort = (0, import_react18.useRef)(null);
3213
+ const [mode, setMode] = (0, import_react18.useState)("backup");
3214
+ const [busy, setBusy] = (0, import_react18.useState)(false);
3215
+ const [error, setError] = (0, import_react18.useState)(null);
3216
+ const [passphrase, setPassphrase] = (0, import_react18.useState)("");
3217
+ const [repeat, setRepeat] = (0, import_react18.useState)("");
3218
+ const [accepted, setAccepted] = (0, import_react18.useState)(false);
3219
+ const [selected, setSelected] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
3220
+ const [backup, setBackup] = (0, import_react18.useState)(null);
3221
+ const [file, setFile] = (0, import_react18.useState)(null);
3222
+ const [restorePreview, setRestorePreview] = (0, import_react18.useState)(null);
3223
+ const [runId, setRunId] = (0, import_react18.useState)(null);
3224
+ const [result, setResult] = (0, import_react18.useState)(null);
3225
+ (0, import_react18.useEffect)(() => () => abort.current?.abort(), []);
3156
3226
  const switchMode = (next) => {
3157
3227
  abort.current?.abort();
3158
3228
  setMode(next);
@@ -3323,7 +3393,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3323
3393
  }
3324
3394
 
3325
3395
  // src/io/ExportPanel.tsx
3326
- var import_react18 = require("react");
3396
+ var import_react19 = require("react");
3327
3397
  var import_controls14 = require("@ai-matrx/design-system/controls");
3328
3398
  var import_download2 = require("@ai-matrx/kit/download");
3329
3399
  var import_confirm_opener5 = require("@ai-matrx/kit/confirm-opener");
@@ -3347,12 +3417,12 @@ function omissionText2(omissions) {
3347
3417
  }
3348
3418
  function ExportPanel({ port, items, onClose }) {
3349
3419
  const confirmed = useConfirmed();
3350
- const logins = (0, import_react18.useMemo)(() => items.filter((i) => i.definitionKey === WEBSITE_LOGIN), [items]);
3351
- const [profile, setProfile] = (0, import_react18.useState)("matrx_login_csv_v1");
3352
- const [selected, setSelected] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
3353
- const [preview, setPreview] = (0, import_react18.useState)(null);
3354
- const [busy, setBusy] = (0, import_react18.useState)(false);
3355
- const [error, setError] = (0, import_react18.useState)(null);
3420
+ const logins = (0, import_react19.useMemo)(() => items.filter((i) => i.definitionKey === WEBSITE_LOGIN), [items]);
3421
+ const [profile, setProfile] = (0, import_react19.useState)("matrx_login_csv_v1");
3422
+ const [selected, setSelected] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
3423
+ const [preview, setPreview] = (0, import_react19.useState)(null);
3424
+ const [busy, setBusy] = (0, import_react19.useState)(false);
3425
+ const [error, setError] = (0, import_react19.useState)(null);
3356
3426
  const format = FORMATS.find((f) => f.value === profile);
3357
3427
  const reasons = new Map(preview?.items.map((p) => [p.item_id, p]) ?? []);
3358
3428
  const eligible = preview?.items.filter((p) => p.eligible).length ?? 0;
@@ -3477,7 +3547,7 @@ function ExportPanel({ port, items, onClose }) {
3477
3547
  }
3478
3548
 
3479
3549
  // src/io/ImportPanel.tsx
3480
- var import_react19 = require("react");
3550
+ var import_react20 = require("react");
3481
3551
  var import_controls15 = require("@ai-matrx/design-system/controls");
3482
3552
 
3483
3553
  // src/io/csv-import.ts
@@ -4336,24 +4406,24 @@ var STATE_BADGE = {
4336
4406
  var ME = "me";
4337
4407
  function ImportPanel({ port, host, items, organizations, onClose, onChanged, limits }) {
4338
4408
  const confirmed = useConfirmed();
4339
- const fileInput = (0, import_react19.useRef)(null);
4340
- const abort = (0, import_react19.useRef)(null);
4341
- const stop = (0, import_react19.useRef)(false);
4342
- const keys = (0, import_react19.useRef)(/* @__PURE__ */ new Map());
4343
- const [source, setSource] = (0, import_react19.useState)("auto");
4344
- const [envText, setEnvText] = (0, import_react19.useState)("");
4345
- const [injectSandbox, setInjectSandbox] = (0, import_react19.useState)(false);
4346
- const [fileName, setFileName] = (0, import_react19.useState)(null);
4347
- const [reading, setReading] = (0, import_react19.useState)(false);
4348
- const [draft, setDraft] = (0, import_react19.useState)(null);
4349
- const [destination, setDestination] = (0, import_react19.useState)(ME);
4350
- const [browserFill, setBrowserFill] = (0, import_react19.useState)(false);
4351
- const [approvedVisible, setApprovedVisible] = (0, import_react19.useState)(false);
4352
- const [selected, setSelected] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
4353
- const [running, setRunning] = (0, import_react19.useState)(null);
4354
- const [done, setDone] = (0, import_react19.useState)(null);
4355
- const [error, setError] = (0, import_react19.useState)(null);
4356
- (0, import_react19.useEffect)(
4409
+ const fileInput = (0, import_react20.useRef)(null);
4410
+ const abort = (0, import_react20.useRef)(null);
4411
+ const stop = (0, import_react20.useRef)(false);
4412
+ const keys = (0, import_react20.useRef)(/* @__PURE__ */ new Map());
4413
+ const [source, setSource] = (0, import_react20.useState)("auto");
4414
+ const [envText, setEnvText] = (0, import_react20.useState)("");
4415
+ const [injectSandbox, setInjectSandbox] = (0, import_react20.useState)(false);
4416
+ const [fileName, setFileName] = (0, import_react20.useState)(null);
4417
+ const [reading, setReading] = (0, import_react20.useState)(false);
4418
+ const [draft, setDraft] = (0, import_react20.useState)(null);
4419
+ const [destination, setDestination] = (0, import_react20.useState)(ME);
4420
+ const [browserFill, setBrowserFill] = (0, import_react20.useState)(false);
4421
+ const [approvedVisible, setApprovedVisible] = (0, import_react20.useState)(false);
4422
+ const [selected, setSelected] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
4423
+ const [running, setRunning] = (0, import_react20.useState)(null);
4424
+ const [done, setDone] = (0, import_react20.useState)(null);
4425
+ const [error, setError] = (0, import_react20.useState)(null);
4426
+ (0, import_react20.useEffect)(
4357
4427
  () => () => {
4358
4428
  abort.current?.abort();
4359
4429
  stop.current = true;
@@ -4362,9 +4432,9 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
4362
4432
  );
4363
4433
  const organizationId = destination === ME ? null : destination;
4364
4434
  const existingIn = (org) => items.filter((i) => org === null ? i.owner.kind === "me" : i.owner.organizationId === org).map((i) => ({ displayName: i.name, loginUrls: i.loginUrls }));
4365
- const existing = (0, import_react19.useMemo)(() => existingIn(organizationId), [items, organizationId]);
4366
- const destinationOptions = (0, import_react19.useMemo)(() => [{ value: ME, label: "Personal" }, ...organizations.map((o) => ({ value: o.id, label: o.name }))], [organizations]);
4367
- const lines = (0, import_react19.useMemo)(
4435
+ const existing = (0, import_react20.useMemo)(() => existingIn(organizationId), [items, organizationId]);
4436
+ const destinationOptions = (0, import_react20.useMemo)(() => [{ value: ME, label: "Personal" }, ...organizations.map((o) => ({ value: o.id, label: o.name }))], [organizations]);
4437
+ const lines = (0, import_react20.useMemo)(
4368
4438
  () => draft?.kind === "file" ? reviewLines(draft.parsed, { organizationId, browserFill, existing, limits, mapping: draft.mapping }) : [],
4369
4439
  [draft, organizationId, browserFill, existing, limits]
4370
4440
  );
@@ -4616,7 +4686,7 @@ function Notices({ draft }) {
4616
4686
  }
4617
4687
 
4618
4688
  // src/ItemList.tsx
4619
- var import_react27 = require("react");
4689
+ var import_react28 = require("react");
4620
4690
  var import_design_system18 = require("@ai-matrx/design-system");
4621
4691
  var import_design_system19 = require("@ai-matrx/design-system");
4622
4692
  var import_controls22 = require("@ai-matrx/design-system/controls");
@@ -4636,14 +4706,14 @@ function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }
4636
4706
  }
4637
4707
 
4638
4708
  // src/ItemPane.tsx
4639
- var import_react26 = require("react");
4709
+ var import_react27 = require("react");
4640
4710
  var import_design_system16 = require("@ai-matrx/design-system");
4641
4711
  var import_design_system17 = require("@ai-matrx/design-system");
4642
4712
  var import_controls21 = require("@ai-matrx/design-system/controls");
4643
4713
  var import_confirm_opener9 = require("@ai-matrx/kit/confirm-opener");
4644
4714
 
4645
4715
  // src/activity/FilesSection.tsx
4646
- var import_react20 = require("react");
4716
+ var import_react21 = require("react");
4647
4717
  var import_controls16 = require("@ai-matrx/design-system/controls");
4648
4718
  var import_design_system13 = require("@ai-matrx/design-system");
4649
4719
  var import_confirm_opener6 = require("@ai-matrx/kit/confirm-opener");
@@ -4659,11 +4729,11 @@ var PROTECTION = [
4659
4729
  function FilesSection({ item, port, editing, onChanged }) {
4660
4730
  const confirmed = useConfirmed();
4661
4731
  const canEdit = editing && item.capabilities.canEdit;
4662
- const [busy, setBusy] = (0, import_react20.useState)(null);
4663
- const [error, setError] = (0, import_react20.useState)(null);
4664
- const [pending, setPending] = (0, import_react20.useState)(null);
4665
- const [dragging, setDragging] = (0, import_react20.useState)(false);
4666
- const picker = (0, import_react20.useRef)(null);
4732
+ const [busy, setBusy] = (0, import_react21.useState)(null);
4733
+ const [error, setError] = (0, import_react21.useState)(null);
4734
+ const [pending, setPending] = (0, import_react21.useState)(null);
4735
+ const [dragging, setDragging] = (0, import_react21.useState)(false);
4736
+ const picker = (0, import_react21.useRef)(null);
4667
4737
  if (!canEdit && item.attachments.length === 0) return null;
4668
4738
  async function run(key, work, fallback) {
4669
4739
  setBusy(key);
@@ -4739,8 +4809,8 @@ function FilesSection({ item, port, editing, onChanged }) {
4739
4809
  );
4740
4810
  }
4741
4811
  function EditableFile({ port, item: it, file: a, busy: b, run: go, onDownload, onTooBig }) {
4742
- const [open, setOpen] = (0, import_react20.useState)(false);
4743
- const replacer = (0, import_react20.useRef)(null);
4812
+ const [open, setOpen] = (0, import_react21.useState)(false);
4813
+ const replacer = (0, import_react21.useRef)(null);
4744
4814
  async function remove() {
4745
4815
  const yes = await (0, import_confirm_opener6.confirm)({ title: `Delete ${a.label}?`, description: "The encrypted file is removed from this item.", confirmLabel: "Delete", variant: "destructive" });
4746
4816
  if (yes) await go(`delete:${a.id}`, () => port.activity.deleteFile(it, a.id), "The file could not be deleted.");
@@ -4798,9 +4868,9 @@ function Protection({ value, locked, onChange }) {
4798
4868
  );
4799
4869
  }
4800
4870
  function NewFile({ file, busy, onAdd, onCancel }) {
4801
- const [label, setLabel] = (0, import_react20.useState)(file.name);
4802
- const [description, setDescription] = (0, import_react20.useState)("");
4803
- const [handling, setHandling] = (0, import_react20.useState)("revealable");
4871
+ const [label, setLabel] = (0, import_react21.useState)(file.name);
4872
+ const [description, setDescription] = (0, import_react21.useState)("");
4873
+ const [handling, setHandling] = (0, import_react21.useState)("revealable");
4804
4874
  async function add() {
4805
4875
  if (handling === "sealed" && !await confirmSeal(label)) return;
4806
4876
  await onAdd({ label: label.trim(), description: description.trim() || null, handling });
@@ -4820,10 +4890,10 @@ function NewFile({ file, busy, onAdd, onCancel }) {
4820
4890
  ] });
4821
4891
  }
4822
4892
  function FileDetailsRows({ file, busy, onSave, onCancel }) {
4823
- const [label, setLabel] = (0, import_react20.useState)(file.label);
4824
- const [description, setDescription] = (0, import_react20.useState)(file.description);
4825
- const [fileName, setFileName] = (0, import_react20.useState)(file.fileName);
4826
- const [handling, setHandling] = (0, import_react20.useState)(file.handling);
4893
+ const [label, setLabel] = (0, import_react21.useState)(file.label);
4894
+ const [description, setDescription] = (0, import_react21.useState)(file.description);
4895
+ const [fileName, setFileName] = (0, import_react21.useState)(file.fileName);
4896
+ const [handling, setHandling] = (0, import_react21.useState)(file.handling);
4827
4897
  const changed = label !== file.label || description !== file.description || fileName !== file.fileName || handling !== file.handling;
4828
4898
  async function save() {
4829
4899
  if (handling === "sealed" && file.handling !== "sealed" && !await confirmSeal(label)) return;
@@ -4850,18 +4920,18 @@ function confirmSeal(label) {
4850
4920
  }
4851
4921
 
4852
4922
  // src/fields/RecoveryCodesRow.tsx
4853
- var import_react21 = require("react");
4923
+ var import_react22 = require("react");
4854
4924
  var import_controls17 = require("@ai-matrx/design-system/controls");
4855
4925
  var import_jsx_runtime21 = require("react/jsx-runtime");
4856
4926
  var MASK4 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
4857
4927
  var say2 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
4858
4928
  function RecoveryCodesRow({ item, field, port, onChanged }) {
4859
4929
  const confirmed = useConfirmed();
4860
- const copyValue = useCopy();
4930
+ const copyValue2 = useCopy();
4861
4931
  const secret = useTransientSecret();
4862
- const [busy, setBusy] = (0, import_react21.useState)(false);
4863
- const [error, setError] = (0, import_react21.useState)(null);
4864
- const [draft, setDraft] = (0, import_react21.useState)(null);
4932
+ const [busy, setBusy] = (0, import_react22.useState)(false);
4933
+ const [error, setError] = (0, import_react22.useState)(null);
4934
+ const [draft, setDraft] = (0, import_react22.useState)(null);
4865
4935
  const canEdit = item.capabilities.canEdit;
4866
4936
  const run = async (step) => {
4867
4937
  setBusy(true);
@@ -4945,7 +5015,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
4945
5015
  children: sealed ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LockGlyph, {}), children: "Sealed" }) : codes ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("ul", { className: "flex flex-col gap-0.5", "aria-label": "Recovery codes", children: [
4946
5016
  codes.map((code, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex min-h-7 items-center gap-1", children: [
4947
5017
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("code", { className: "min-w-0 flex-1 break-all font-mono text-sm text-foreground", children: code }),
4948
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CopyGlyph, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue(code, "Recovery code") }),
5018
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CopyGlyph, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue2(code, "Recovery code") }),
4949
5019
  canEdit ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_controls17.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CheckGlyph, {}), disabled: busy, onClick: () => void markUsed(i), children: "Mark used" }) : null
4950
5020
  ] }, `${i}-${code}`)),
4951
5021
  error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { role: "alert", className: "text-xs text-destructive", children: error }) : null
@@ -5096,7 +5166,7 @@ function targetLabel(t) {
5096
5166
  }
5097
5167
 
5098
5168
  // src/extension/UseOnSiteButton.tsx
5099
- var import_react22 = require("react");
5169
+ var import_react23 = require("react");
5100
5170
  var import_controls18 = require("@ai-matrx/design-system/controls");
5101
5171
  var import_jsx_runtime22 = require("react/jsx-runtime");
5102
5172
  function canUseOnSite(item, pageUrl) {
@@ -5104,7 +5174,7 @@ function canUseOnSite(item, pageUrl) {
5104
5174
  }
5105
5175
  function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5106
5176
  const notify = useNotify();
5107
- const [busy, setBusy] = (0, import_react22.useState)(false);
5177
+ const [busy, setBusy] = (0, import_react23.useState)(false);
5108
5178
  if (!canUseOnSite(item, pageUrl)) return null;
5109
5179
  const site = pageSite(pageUrl);
5110
5180
  const run = async () => {
@@ -5123,7 +5193,7 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5123
5193
  }
5124
5194
 
5125
5195
  // src/sharing/SharePanel.tsx
5126
- var import_react25 = require("react");
5196
+ var import_react26 = require("react");
5127
5197
  var import_confirm_opener8 = require("@ai-matrx/kit/confirm-opener");
5128
5198
  var import_controls20 = require("@ai-matrx/design-system/controls");
5129
5199
  var import_design_system15 = require("@ai-matrx/design-system");
@@ -5180,7 +5250,7 @@ function shareSummary(grants) {
5180
5250
  var MEMBER_CHOICE_DEFAULT = "default";
5181
5251
 
5182
5252
  // src/sharing/parts.tsx
5183
- var import_react23 = require("react");
5253
+ var import_react24 = require("react");
5184
5254
  var import_design_system14 = require("@ai-matrx/design-system");
5185
5255
  var import_jsx_runtime23 = require("react/jsx-runtime");
5186
5256
  var message = (e, fallback) => {
@@ -5189,9 +5259,9 @@ var message = (e, fallback) => {
5189
5259
  };
5190
5260
  function useAction() {
5191
5261
  const confirmed = useConfirmed();
5192
- const [busy, setBusy] = (0, import_react23.useState)(null);
5193
- const [error, setError] = (0, import_react23.useState)(null);
5194
- const [notice, setNotice] = (0, import_react23.useState)(null);
5262
+ const [busy, setBusy] = (0, import_react24.useState)(null);
5263
+ const [error, setError] = (0, import_react24.useState)(null);
5264
+ const [notice, setNotice] = (0, import_react24.useState)(null);
5195
5265
  async function run(key, fn, done) {
5196
5266
  setBusy(key);
5197
5267
  setError(null);
@@ -5225,7 +5295,7 @@ function StatusLine({ error, notice }) {
5225
5295
  }
5226
5296
 
5227
5297
  // src/sharing/MovePanel.tsx
5228
- var import_react24 = require("react");
5298
+ var import_react25 = require("react");
5229
5299
  var import_confirm_opener7 = require("@ai-matrx/kit/confirm-opener");
5230
5300
  var import_controls19 = require("@ai-matrx/design-system/controls");
5231
5301
  var import_jsx_runtime24 = require("react/jsx-runtime");
@@ -5234,9 +5304,9 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5234
5304
  const { busy, error, notice, run, setNotice } = useAction();
5235
5305
  const moves = moveDestinations(item, organizations);
5236
5306
  const copies = copyDestinations(organizations, item);
5237
- const [moveTo, setMoveTo] = (0, import_react24.useState)("");
5238
- const [copyTo, setCopyTo] = (0, import_react24.useState)("");
5239
- const [email, setEmail] = (0, import_react24.useState)("");
5307
+ const [moveTo, setMoveTo] = (0, import_react25.useState)("");
5308
+ const [copyTo, setCopyTo] = (0, import_react25.useState)("");
5309
+ const [email, setEmail] = (0, import_react25.useState)("");
5240
5310
  const passkey = isPasskey(item);
5241
5311
  const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
5242
5312
  const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
@@ -5317,11 +5387,11 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5317
5387
  // src/sharing/SharePanel.tsx
5318
5388
  var import_jsx_runtime25 = require("react/jsx-runtime");
5319
5389
  function useGrants(port, item) {
5320
- const [grants, setGrants] = (0, import_react25.useState)(null);
5321
- const [loadError, setLoadError] = (0, import_react25.useState)(null);
5322
- const [nonce, setNonce] = (0, import_react25.useState)(0);
5390
+ const [grants, setGrants] = (0, import_react26.useState)(null);
5391
+ const [loadError, setLoadError] = (0, import_react26.useState)(null);
5392
+ const [nonce, setNonce] = (0, import_react26.useState)(0);
5323
5393
  const allowed = item.capabilities.canManage;
5324
- (0, import_react25.useEffect)(() => {
5394
+ (0, import_react26.useEffect)(() => {
5325
5395
  if (!allowed) return;
5326
5396
  let live = true;
5327
5397
  setLoadError(null);
@@ -5338,9 +5408,9 @@ function useGrants(port, item) {
5338
5408
  function SharePanel({ item, port, organizations, onClose, onChanged }) {
5339
5409
  const { grants, setGrants, loadError, reload } = useGrants(port, item);
5340
5410
  const { busy, error, notice, run } = useAction();
5341
- const [email, setEmail] = (0, import_react25.useState)("");
5342
- const [level, setLevel] = (0, import_react25.useState)("use");
5343
- const [more, setMore] = (0, import_react25.useState)(false);
5411
+ const [email, setEmail] = (0, import_react26.useState)("");
5412
+ const [level, setLevel] = (0, import_react26.useState)("use");
5413
+ const [more, setMore] = (0, import_react26.useState)(false);
5344
5414
  const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
5345
5415
  const orgName = item.owner.label;
5346
5416
  const people = (grants ?? []).filter((g) => g.kind === "person");
@@ -5462,8 +5532,8 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5462
5532
  function IntoOrganization({ item, port, organizations, grants, onShared }) {
5463
5533
  const { busy, error, notice, run } = useAction();
5464
5534
  const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
5465
- const [target, setTarget] = (0, import_react25.useState)("");
5466
- const [level, setLevel] = (0, import_react25.useState)("use");
5535
+ const [target, setTarget] = (0, import_react26.useState)("");
5536
+ const [level, setLevel] = (0, import_react26.useState)("use");
5467
5537
  const chosen = open.find((o) => o.id === target);
5468
5538
  if (item.owner.kind !== "me") return null;
5469
5539
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Section, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
@@ -5498,10 +5568,10 @@ var CHOICES = [
5498
5568
  { value: "editor", label: "Can edit", meta: "See and change" }
5499
5569
  ];
5500
5570
  function MemberAccess({ port, organizationId, organizationName }) {
5501
- const [list, setList] = (0, import_react25.useState)(null);
5502
- const [loadError, setLoadError] = (0, import_react25.useState)(null);
5571
+ const [list, setList] = (0, import_react26.useState)(null);
5572
+ const [loadError, setLoadError] = (0, import_react26.useState)(null);
5503
5573
  const { busy, error, run } = useAction();
5504
- (0, import_react25.useEffect)(() => {
5574
+ (0, import_react26.useEffect)(() => {
5505
5575
  let live = true;
5506
5576
  port.sharing.memberAccess(organizationId).then(
5507
5577
  (l) => live && setList(l),
@@ -5533,9 +5603,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
5533
5603
  ] });
5534
5604
  }
5535
5605
  function SharingSummary({ item, port, className }) {
5536
- const [text, setText] = (0, import_react25.useState)("");
5606
+ const [text, setText] = (0, import_react26.useState)("");
5537
5607
  const allowed = item.capabilities.canManage;
5538
- (0, import_react25.useEffect)(() => {
5608
+ (0, import_react26.useEffect)(() => {
5539
5609
  if (!allowed) return;
5540
5610
  let live = true;
5541
5611
  port.sharing.grants(item).then(
@@ -5560,8 +5630,8 @@ function ItemPane(props) {
5560
5630
  const editing = mode !== "view";
5561
5631
  const seedName = seed?.name ?? "";
5562
5632
  const seedUrl = seed?.url ?? "";
5563
- const [loaded, setLoaded] = (0, import_react26.useState)({});
5564
- const base = (0, import_react26.useMemo)(() => {
5633
+ const [loaded, setLoaded] = (0, import_react27.useState)({});
5634
+ const base = (0, import_react27.useMemo)(() => {
5565
5635
  const b = draftOf(item);
5566
5636
  if (!item) {
5567
5637
  b.name = seedName;
@@ -5570,22 +5640,22 @@ function ItemPane(props) {
5570
5640
  b.values = { ...loaded };
5571
5641
  return b;
5572
5642
  }, [item, seedName, seedUrl, loaded]);
5573
- const [draft, setDraft] = (0, import_react26.useState)(base);
5574
- const [tagsText, setTagsText] = (0, import_react26.useState)(base.tags.join(", "));
5575
- const [showTags, setShowTags] = (0, import_react26.useState)(false);
5576
- const [showDescription, setShowDescription] = (0, import_react26.useState)(false);
5577
- const [owner, setOwner] = (0, import_react26.useState)(defaultOwner ?? "me");
5578
- const [recipient, setRecipient] = (0, import_react26.useState)("");
5579
- const [generatePrivately, setGeneratePrivately] = (0, import_react26.useState)(false);
5580
- const [busy, setBusy] = (0, import_react26.useState)(false);
5581
- const [error, setError] = (0, import_react26.useState)(null);
5582
- const [destinations, setDestinations] = (0, import_react26.useState)({});
5643
+ const [draft, setDraft] = (0, import_react27.useState)(base);
5644
+ const [tagsText, setTagsText] = (0, import_react27.useState)(base.tags.join(", "));
5645
+ const [showTags, setShowTags] = (0, import_react27.useState)(false);
5646
+ const [showDescription, setShowDescription] = (0, import_react27.useState)(false);
5647
+ const [owner, setOwner] = (0, import_react27.useState)(defaultOwner ?? "me");
5648
+ const [recipient, setRecipient] = (0, import_react27.useState)("");
5649
+ const [generatePrivately, setGeneratePrivately] = (0, import_react27.useState)(false);
5650
+ const [busy, setBusy] = (0, import_react27.useState)(false);
5651
+ const [error, setError] = (0, import_react27.useState)(null);
5652
+ const [destinations, setDestinations] = (0, import_react27.useState)({});
5583
5653
  const dirty = editing && isDirty(base, draft);
5584
5654
  const declared = definition?.fields ?? [];
5585
- const prev = (0, import_react26.useRef)(null);
5586
- const paneRef = (0, import_react26.useRef)(null);
5655
+ const prev = (0, import_react27.useRef)(null);
5656
+ const paneRef = (0, import_react27.useRef)(null);
5587
5657
  const room = useRoomOf(paneRef);
5588
- (0, import_react26.useEffect)(() => {
5658
+ (0, import_react27.useEffect)(() => {
5589
5659
  const was = prev.current;
5590
5660
  const id = item?.id ?? null;
5591
5661
  if (was && was.id === id && was.mode === mode && editing) {
@@ -5598,18 +5668,18 @@ function ItemPane(props) {
5598
5668
  }
5599
5669
  prev.current = { base, id, mode };
5600
5670
  }, [base, mode, item?.id, editing]);
5601
- (0, import_react26.useEffect)(() => {
5671
+ (0, import_react27.useEffect)(() => {
5602
5672
  setLoaded({});
5603
5673
  setShowTags(false);
5604
5674
  setShowDescription(false);
5605
5675
  }, [item?.id, mode]);
5606
- (0, import_react26.useEffect)(() => onDirty(dirty), [dirty, onDirty]);
5676
+ (0, import_react27.useEffect)(() => onDirty(dirty), [dirty, onDirty]);
5607
5677
  const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
5608
- (0, import_react26.useEffect)(() => {
5678
+ (0, import_react27.useEffect)(() => {
5609
5679
  if (editing && dirty) keepDraft(keepKey, item?.updatedAt ?? "new", draft);
5610
5680
  else if (!editing) dropKeptDraft(keepKey);
5611
5681
  }, [editing, dirty, draft, keepKey, item?.updatedAt]);
5612
- (0, import_react26.useEffect)(() => {
5682
+ (0, import_react27.useEffect)(() => {
5613
5683
  if (!editing || !item) return;
5614
5684
  let live = true;
5615
5685
  for (const f of item.fields) {
@@ -5955,8 +6025,8 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
5955
6025
  const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
5956
6026
  const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
5957
6027
  const ordered = [...pinned, ...rest];
5958
- const listRef = (0, import_react27.useRef)(null);
5959
- (0, import_react27.useEffect)(() => {
6028
+ const listRef = (0, import_react28.useRef)(null);
6029
+ (0, import_react28.useEffect)(() => {
5960
6030
  if (selectedId) listRef.current?.querySelector(`[data-item="${selectedId}"]`)?.scrollIntoView({ block: "nearest" });
5961
6031
  }, [selectedId, items.length]);
5962
6032
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -6007,14 +6077,14 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
6007
6077
  const confirmed = useConfirmed();
6008
6078
  const copy = useCopy();
6009
6079
  const notify = useNotify();
6010
- const [busy, setBusy] = (0, import_react27.useState)(false);
6080
+ const [busy, setBusy] = (0, import_react28.useState)(false);
6011
6081
  const user = item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed");
6012
6082
  const secret = item.fields.find((f) => f.key === "password" && f.handling === "revealable");
6013
6083
  const quick = async (key, label) => {
6014
6084
  setBusy(true);
6015
6085
  try {
6016
6086
  const v = await confirmed(() => port.reveal(item, key));
6017
- await copy(v, label);
6087
+ await copy(v, label, { secret: key !== user?.key || user.handling !== "visible" });
6018
6088
  } catch (e) {
6019
6089
  if (!wasCancelled(e)) notify(e instanceof Error ? e.message : `${label} could not be read`, "error");
6020
6090
  } finally {
@@ -6047,7 +6117,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
6047
6117
  }
6048
6118
 
6049
6119
  // src/lists/TrashView.tsx
6050
- var import_react29 = require("react");
6120
+ var import_react30 = require("react");
6051
6121
  var import_controls24 = require("@ai-matrx/design-system/controls");
6052
6122
 
6053
6123
  // src/lists/logic.ts
@@ -6120,16 +6190,16 @@ function refusalText(reason) {
6120
6190
  }
6121
6191
 
6122
6192
  // src/lists/RestorePanel.tsx
6123
- var import_react28 = require("react");
6193
+ var import_react29 = require("react");
6124
6194
  var import_controls23 = require("@ai-matrx/design-system/controls");
6125
6195
  var import_jsx_runtime28 = require("react/jsx-runtime");
6126
6196
  var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
6127
6197
  function RestorePanel({ lists, item, restore, onClose }) {
6128
- const [preview, setPreview] = (0, import_react28.useState)(null);
6129
- const [error, setError] = (0, import_react28.useState)(null);
6130
- const [busy, setBusy] = (0, import_react28.useState)(false);
6131
- const [loading, setLoading] = (0, import_react28.useState)(Boolean(lists.preview));
6132
- (0, import_react28.useEffect)(() => {
6198
+ const [preview, setPreview] = (0, import_react29.useState)(null);
6199
+ const [error, setError] = (0, import_react29.useState)(null);
6200
+ const [busy, setBusy] = (0, import_react29.useState)(false);
6201
+ const [loading, setLoading] = (0, import_react29.useState)(Boolean(lists.preview));
6202
+ (0, import_react29.useEffect)(() => {
6133
6203
  if (!lists.preview) return;
6134
6204
  let live = true;
6135
6205
  lists.preview(item).then(
@@ -6189,10 +6259,10 @@ function RestorePanel({ lists, item, restore, onClose }) {
6189
6259
  var import_jsx_runtime29 = require("react/jsx-runtime");
6190
6260
  function TrashView({ port, deleted, query, header, onChanged }) {
6191
6261
  const confirmed = useConfirmed();
6192
- const [busyId, setBusyId] = (0, import_react29.useState)(null);
6193
- const [message2, setMessage] = (0, import_react29.useState)(null);
6262
+ const [busyId, setBusyId] = (0, import_react30.useState)(null);
6263
+ const [message2, setMessage] = (0, import_react30.useState)(null);
6194
6264
  const shown = deleted.filter((i) => matchesQuery2(i, query));
6195
- const [restoring, setRestoring] = (0, import_react29.useState)(null);
6265
+ const [restoring, setRestoring] = (0, import_react30.useState)(null);
6196
6266
  const restore = async (item, deletionId) => {
6197
6267
  setBusyId(item.id);
6198
6268
  setMessage(null);
@@ -6227,15 +6297,15 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6227
6297
  }
6228
6298
 
6229
6299
  // src/NewItemFlow.tsx
6230
- var import_react30 = require("react");
6300
+ var import_react31 = require("react");
6231
6301
  var import_design_system20 = require("@ai-matrx/design-system");
6232
6302
  var import_controls25 = require("@ai-matrx/design-system/controls");
6233
6303
  var import_jsx_runtime30 = require("react/jsx-runtime");
6234
6304
  function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6235
- const [search, setSearch] = (0, import_react30.useState)("");
6236
- const guess = (0, import_react30.useMemo)(() => inferFromUrl(url, definitions), [url, definitions]);
6305
+ const [search, setSearch] = (0, import_react31.useState)("");
6306
+ const guess = (0, import_react31.useMemo)(() => inferFromUrl(url, definitions), [url, definitions]);
6237
6307
  const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
6238
- const matches = (0, import_react30.useMemo)(() => {
6308
+ const matches = (0, import_react31.useMemo)(() => {
6239
6309
  const q = search.trim().toLowerCase();
6240
6310
  if (!q) return [];
6241
6311
  return definitions.filter((d) => `${d.label} ${d.key} ${d.providerKey ?? ""} ${FAMILY_LABELS[d.family] ?? ""}`.toLowerCase().includes(q)).slice(0, 60);
@@ -6299,7 +6369,7 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6299
6369
  }
6300
6370
 
6301
6371
  // src/sharing/SecureLinkPanel.tsx
6302
- var import_react31 = require("react");
6372
+ var import_react32 = require("react");
6303
6373
  var import_confirm_opener10 = require("@ai-matrx/kit/confirm-opener");
6304
6374
  var import_design_system21 = require("@ai-matrx/design-system");
6305
6375
  var import_controls26 = require("@ai-matrx/design-system/controls");
@@ -6381,20 +6451,20 @@ var import_jsx_runtime31 = require("react/jsx-runtime");
6381
6451
  function SecureLinkPanel({ item, port, onClose }) {
6382
6452
  const sharing = port.sharing;
6383
6453
  const { busy, error, notice, run, setNotice } = useAction();
6384
- const [remedy, setRemedy] = (0, import_react31.useState)(null);
6385
- const [options, setOptions] = (0, import_react31.useState)(null);
6386
- const [optionsError, setOptionsError] = (0, import_react31.useState)(null);
6387
- const [sent, setSent] = (0, import_react31.useState)(null);
6388
- const [sentError, setSentError] = (0, import_react31.useState)(null);
6389
- const [nonce, setNonce] = (0, import_react31.useState)(0);
6390
- const [email, setEmail] = (0, import_react31.useState)("");
6391
- const [phone, setPhone] = (0, import_react31.useState)("");
6392
- const [name, setName] = (0, import_react31.useState)("");
6393
- const [linkBy, setLinkBy] = (0, import_react31.useState)("email");
6394
- const [fields, setFields] = (0, import_react31.useState)([]);
6395
- const [note, setNote] = (0, import_react31.useState)("");
6396
- const [sameChannelSent, setSameChannelSent] = (0, import_react31.useState)(false);
6397
- (0, import_react31.useEffect)(() => {
6454
+ const [remedy, setRemedy] = (0, import_react32.useState)(null);
6455
+ const [options, setOptions] = (0, import_react32.useState)(null);
6456
+ const [optionsError, setOptionsError] = (0, import_react32.useState)(null);
6457
+ const [sent, setSent] = (0, import_react32.useState)(null);
6458
+ const [sentError, setSentError] = (0, import_react32.useState)(null);
6459
+ const [nonce, setNonce] = (0, import_react32.useState)(0);
6460
+ const [email, setEmail] = (0, import_react32.useState)("");
6461
+ const [phone, setPhone] = (0, import_react32.useState)("");
6462
+ const [name, setName] = (0, import_react32.useState)("");
6463
+ const [linkBy, setLinkBy] = (0, import_react32.useState)("email");
6464
+ const [fields, setFields] = (0, import_react32.useState)([]);
6465
+ const [note, setNote] = (0, import_react32.useState)("");
6466
+ const [sameChannelSent, setSameChannelSent] = (0, import_react32.useState)(false);
6467
+ (0, import_react32.useEffect)(() => {
6398
6468
  let live = true;
6399
6469
  setOptionsError(null);
6400
6470
  sharing.secureLinkOptions(item).then(
@@ -6409,7 +6479,7 @@ function SecureLinkPanel({ item, port, onClose }) {
6409
6479
  live = false;
6410
6480
  };
6411
6481
  }, [sharing, item]);
6412
- (0, import_react31.useEffect)(() => {
6482
+ (0, import_react32.useEffect)(() => {
6413
6483
  const list = sharing.sentSecureLinks;
6414
6484
  if (!list) return;
6415
6485
  let live = true;
@@ -6422,9 +6492,9 @@ function SecureLinkPanel({ item, port, onClose }) {
6422
6492
  live = false;
6423
6493
  };
6424
6494
  }, [sharing, item, nonce]);
6425
- const [phoneTyped, setPhoneTyped] = (0, import_react31.useState)(false);
6426
- const prefilled = (0, import_react31.useRef)(false);
6427
- (0, import_react31.useEffect)(() => {
6495
+ const [phoneTyped, setPhoneTyped] = (0, import_react32.useState)(false);
6496
+ const prefilled = (0, import_react32.useRef)(false);
6497
+ (0, import_react32.useEffect)(() => {
6428
6498
  const lookup = sharing.phoneOnFile;
6429
6499
  if (!lookup || phoneTyped) return;
6430
6500
  const clear = () => {
@@ -6578,7 +6648,7 @@ function sentMeta(row, options) {
6578
6648
  }
6579
6649
 
6580
6650
  // src/devices/DevicesPanel.tsx
6581
- var import_react32 = require("react");
6651
+ var import_react33 = require("react");
6582
6652
  var import_confirm_opener11 = require("@ai-matrx/kit/confirm-opener");
6583
6653
  var import_controls27 = require("@ai-matrx/design-system/controls");
6584
6654
 
@@ -6668,10 +6738,10 @@ function ErrorLine2({ text }) {
6668
6738
  function DevicesPanel({ port, onClose }) {
6669
6739
  const confirmed = useConfirmed();
6670
6740
  const notify = useNotify();
6671
- const [devices, setDevices] = (0, import_react32.useState)(null);
6672
- const [error, setError] = (0, import_react32.useState)(null);
6673
- const [busyId, setBusyId] = (0, import_react32.useState)(null);
6674
- const load = (0, import_react32.useCallback)(async () => {
6741
+ const [devices, setDevices] = (0, import_react33.useState)(null);
6742
+ const [error, setError] = (0, import_react33.useState)(null);
6743
+ const [busyId, setBusyId] = (0, import_react33.useState)(null);
6744
+ const load = (0, import_react33.useCallback)(async () => {
6675
6745
  setError(null);
6676
6746
  try {
6677
6747
  setDevices(await port.devices.list());
@@ -6679,7 +6749,7 @@ function DevicesPanel({ port, onClose }) {
6679
6749
  setError(messageOf3(e, "Your browsers could not be read."));
6680
6750
  }
6681
6751
  }, [port]);
6682
- (0, import_react32.useEffect)(() => {
6752
+ (0, import_react33.useEffect)(() => {
6683
6753
  void load();
6684
6754
  }, [load]);
6685
6755
  const revoke = async (device) => {
@@ -6737,11 +6807,11 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6737
6807
  const where = isMac ? "the Mac app" : "the extension";
6738
6808
  const passkeys = port.devices.passkeys;
6739
6809
  const here = passkeys?.available() ?? false;
6740
- const [methods, setMethods] = (0, import_react32.useState)(null);
6741
- const [busy, setBusy] = (0, import_react32.useState)(null);
6742
- const [error, setError] = (0, import_react32.useState)(null);
6743
- const [approvedUntil, setApprovedUntil] = (0, import_react32.useState)(null);
6744
- const load = (0, import_react32.useCallback)(async () => {
6810
+ const [methods, setMethods] = (0, import_react33.useState)(null);
6811
+ const [busy, setBusy] = (0, import_react33.useState)(null);
6812
+ const [error, setError] = (0, import_react33.useState)(null);
6813
+ const [approvedUntil, setApprovedUntil] = (0, import_react33.useState)(null);
6814
+ const load = (0, import_react33.useCallback)(async () => {
6745
6815
  setError(null);
6746
6816
  try {
6747
6817
  setMethods(await port.devices.stepUpMethods());
@@ -6749,7 +6819,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6749
6819
  setError(messageOf3(e, "Your account could not be checked."));
6750
6820
  }
6751
6821
  }, [port]);
6752
- (0, import_react32.useEffect)(() => {
6822
+ (0, import_react33.useEffect)(() => {
6753
6823
  if (key && here) void load();
6754
6824
  }, [key, here, load]);
6755
6825
  const approve = async () => {
@@ -6837,7 +6907,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6837
6907
  }
6838
6908
 
6839
6909
  // src/native/NativeImportPanel.tsx
6840
- var import_react34 = require("react");
6910
+ var import_react35 = require("react");
6841
6911
  var import_confirm_opener12 = require("@ai-matrx/kit/confirm-opener");
6842
6912
  var import_controls28 = require("@ai-matrx/design-system/controls");
6843
6913
 
@@ -6900,19 +6970,19 @@ async function loadFullPreview(bridge, operationId, current) {
6900
6970
  }
6901
6971
 
6902
6972
  // src/native/use-native-import.ts
6903
- var import_react33 = require("react");
6973
+ var import_react34 = require("react");
6904
6974
  var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
6905
6975
  var RESTART = "Your account changed. The import was stopped; start it again.";
6906
6976
  function useNativeImport(bridge, stillAllowed, onImported) {
6907
- const [screen, setScreen] = (0, import_react33.useState)({ kind: "idle", message: null });
6908
- const [busy, setBusy] = (0, import_react33.useState)(false);
6909
- const generation = (0, import_react33.useRef)(0);
6910
- const mounted = (0, import_react33.useRef)(false);
6911
- const op = (0, import_react33.useRef)(null);
6912
- const last = (0, import_react33.useRef)(null);
6913
- const timer2 = (0, import_react33.useRef)(null);
6914
- const polls = (0, import_react33.useRef)(0);
6915
- const refreshRef = (0, import_react33.useRef)(async () => void 0);
6977
+ const [screen, setScreen] = (0, import_react34.useState)({ kind: "idle", message: null });
6978
+ const [busy, setBusy] = (0, import_react34.useState)(false);
6979
+ const generation = (0, import_react34.useRef)(0);
6980
+ const mounted = (0, import_react34.useRef)(false);
6981
+ const op = (0, import_react34.useRef)(null);
6982
+ const last = (0, import_react34.useRef)(null);
6983
+ const timer2 = (0, import_react34.useRef)(null);
6984
+ const polls = (0, import_react34.useRef)(0);
6985
+ const refreshRef = (0, import_react34.useRef)(async () => void 0);
6916
6986
  const current = (g) => mounted.current && g === generation.current;
6917
6987
  const stopPolling = () => {
6918
6988
  if (timer2.current !== null) clearTimeout(timer2.current);
@@ -7081,9 +7151,9 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7081
7151
  setBusy(false);
7082
7152
  setScreen({ kind: "idle", message: null });
7083
7153
  };
7084
- const invalidateRef = (0, import_react33.useRef)(invalidate);
7154
+ const invalidateRef = (0, import_react34.useRef)(invalidate);
7085
7155
  invalidateRef.current = invalidate;
7086
- (0, import_react33.useEffect)(() => {
7156
+ (0, import_react34.useEffect)(() => {
7087
7157
  mounted.current = true;
7088
7158
  const off = bridge.subscribe?.(() => {
7089
7159
  if (op.current) invalidateRef.current(RESTART);
@@ -7115,14 +7185,14 @@ function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizat
7115
7185
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
7116
7186
  }
7117
7187
  function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
7118
- const options = (0, import_react34.useMemo)(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
7119
- const [organizationId, setOrganizationId] = (0, import_react34.useState)(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7120
- const [limits, setLimits] = (0, import_react34.useState)(null);
7121
- const [limitError, setLimitError] = (0, import_react34.useState)(null);
7188
+ const options = (0, import_react35.useMemo)(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
7189
+ const [organizationId, setOrganizationId] = (0, import_react35.useState)(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7190
+ const [limits, setLimits] = (0, import_react35.useState)(null);
7191
+ const [limitError, setLimitError] = (0, import_react35.useState)(null);
7122
7192
  const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
7123
7193
  const { screen, busy } = flow;
7124
7194
  const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
7125
- (0, import_react34.useEffect)(() => {
7195
+ (0, import_react35.useEffect)(() => {
7126
7196
  if (!readLimits || !organizationId) return;
7127
7197
  let live = true;
7128
7198
  setLimits(null);
@@ -7183,20 +7253,20 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
7183
7253
  }
7184
7254
 
7185
7255
  // src/extension/PageView.tsx
7186
- var import_react38 = require("react");
7256
+ var import_react39 = require("react");
7187
7257
  var import_design_system23 = require("@ai-matrx/design-system");
7188
7258
  var import_controls32 = require("@ai-matrx/design-system/controls");
7189
7259
 
7190
7260
  // src/extension/CaptureCard.tsx
7191
- var import_react35 = require("react");
7261
+ var import_react36 = require("react");
7192
7262
  var import_controls29 = require("@ai-matrx/design-system/controls");
7193
7263
  var import_jsx_runtime34 = require("react/jsx-runtime");
7194
7264
  var SEARCH_FROM = 4;
7195
7265
  function CaptureCard({ capture, onChanged }) {
7196
- const prompt = (0, import_react35.useSyncExternalStore)(capture.subscribe, capture.get, capture.get);
7266
+ const prompt = (0, import_react36.useSyncExternalStore)(capture.subscribe, capture.get, capture.get);
7197
7267
  const notify = useNotify();
7198
- const [busy, setBusy] = (0, import_react35.useState)(false);
7199
- const [q, setQ] = (0, import_react35.useState)("");
7268
+ const [busy, setBusy] = (0, import_react36.useState)(false);
7269
+ const [q, setQ] = (0, import_react36.useState)("");
7200
7270
  if (!prompt) return null;
7201
7271
  const decide = async (d) => {
7202
7272
  setBusy(true);
@@ -7252,15 +7322,15 @@ function CaptureCard({ capture, onChanged }) {
7252
7322
  }
7253
7323
 
7254
7324
  // src/extension/FillSetupCard.tsx
7255
- var import_react36 = require("react");
7325
+ var import_react37 = require("react");
7256
7326
  var import_controls30 = require("@ai-matrx/design-system/controls");
7257
7327
  var import_jsx_runtime35 = require("react/jsx-runtime");
7258
7328
  function FillSetupCard({ fillSetup }) {
7259
7329
  const notify = useNotify();
7260
- const state = (0, import_react36.useSyncExternalStore)(fillSetup.subscribe, fillSetup.get, fillSetup.get);
7261
- const box = (0, import_react36.useRef)(null);
7262
- const [busy, setBusy] = (0, import_react36.useState)(false);
7263
- const [error, setError] = (0, import_react36.useState)(null);
7330
+ const state = (0, import_react37.useSyncExternalStore)(fillSetup.subscribe, fillSetup.get, fillSetup.get);
7331
+ const box = (0, import_react37.useRef)(null);
7332
+ const [busy, setBusy] = (0, import_react37.useState)(false);
7333
+ const [error, setError] = (0, import_react37.useState)(null);
7264
7334
  if (state.status !== "off") return null;
7265
7335
  const finish = async (run) => {
7266
7336
  setBusy(true);
@@ -7325,7 +7395,7 @@ function FillSetupCard({ fillSetup }) {
7325
7395
  }
7326
7396
 
7327
7397
  // src/extension/PageGenerator.tsx
7328
- var import_react37 = require("react");
7398
+ var import_react38 = require("react");
7329
7399
  var import_design_system22 = require("@ai-matrx/design-system");
7330
7400
  var import_controls31 = require("@ai-matrx/design-system/controls");
7331
7401
  var import_jsx_runtime36 = require("react/jsx-runtime");
@@ -7334,10 +7404,10 @@ function PageGenerator({ fields }) {
7334
7404
  const limits = useGeneratorLimitsSource();
7335
7405
  const copy = useCopy();
7336
7406
  const held = useTransientSecret(HOLD_MS);
7337
- const [open, setOpen] = (0, import_react37.useState)(false);
7338
- const [busy, setBusy] = (0, import_react37.useState)(false);
7339
- const [targets, setTargets] = (0, import_react37.useState)([]);
7340
- const [said, setSaid] = (0, import_react37.useState)(null);
7407
+ const [open, setOpen] = (0, import_react38.useState)(false);
7408
+ const [busy, setBusy] = (0, import_react38.useState)(false);
7409
+ const [targets, setTargets] = (0, import_react38.useState)([]);
7410
+ const [said, setSaid] = (0, import_react38.useState)(null);
7341
7411
  if (!limits) return null;
7342
7412
  const say3 = setSaid;
7343
7413
  const put = async (targetId, value2) => {
@@ -7401,8 +7471,8 @@ function PageGenerator({ fields }) {
7401
7471
  // src/extension/PageView.tsx
7402
7472
  var import_jsx_runtime37 = require("react/jsx-runtime");
7403
7473
  function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
7404
- const [running, setRunning] = (0, import_react38.useState)(null);
7405
- const [said, setSaid] = (0, import_react38.useState)(null);
7474
+ const [running, setRunning] = (0, import_react39.useState)(null);
7475
+ const [said, setSaid] = (0, import_react39.useState)(null);
7406
7476
  const site = pageSite(page.url);
7407
7477
  const state = page.matchState ?? { status: "ready" };
7408
7478
  const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
@@ -7486,7 +7556,7 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7486
7556
  const confirmed = useConfirmed();
7487
7557
  const copy = useCopy();
7488
7558
  const notify = useNotify();
7489
- const [reading, setReading] = (0, import_react38.useState)(false);
7559
+ const [reading, setReading] = (0, import_react39.useState)(false);
7490
7560
  const usable = item?.capabilities.canUse ?? false;
7491
7561
  const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
7492
7562
  const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
@@ -7531,7 +7601,7 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7531
7601
  }
7532
7602
 
7533
7603
  // src/Sidebar.tsx
7534
- var import_react39 = require("react");
7604
+ var import_react40 = require("react");
7535
7605
  var import_design_system24 = require("@ai-matrx/design-system");
7536
7606
  var import_controls33 = require("@ai-matrx/design-system/controls");
7537
7607
  var import_jsx_runtime38 = require("react/jsx-runtime");
@@ -7614,7 +7684,7 @@ function Group({ title, children }) {
7614
7684
  ] });
7615
7685
  }
7616
7686
  function Sidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
7617
- const [tagsOpen, setTagsOpen] = (0, import_react39.useState)(view.startsWith("tag:"));
7687
+ const [tagsOpen, setTagsOpen] = (0, import_react40.useState)(view.startsWith("tag:"));
7618
7688
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("nav", { "aria-label": "Vault", className: "flex h-full min-h-0 flex-col border-r border-sidebar-border bg-sidebar-background text-sidebar-foreground", children: [
7619
7689
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
7620
7690
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
@@ -7674,8 +7744,8 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
7674
7744
  } : void 0;
7675
7745
  function ImportWithLimits(props) {
7676
7746
  const { knobs, ...rest } = props;
7677
- const [state, setState] = (0, import_react40.useState)(null);
7678
- (0, import_react40.useEffect)(() => {
7747
+ const [state, setState] = (0, import_react41.useState)(null);
7748
+ (0, import_react41.useEffect)(() => {
7679
7749
  if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
7680
7750
  knobs().then(
7681
7751
  (r) => {
@@ -7692,31 +7762,55 @@ function ImportWithLimits(props) {
7692
7762
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
7693
7763
  }
7694
7764
  function VaultApp(props) {
7695
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(NoticeProvider, { notify: props.notify, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Workspace, { ...props }) }) }) }) });
7765
+ const lock = props.host?.lock;
7766
+ const locked = useLocked(lock);
7767
+ const port = (0, import_react41.useMemo)(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
7768
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LockedScreen, { lock }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Workspace, { ...props, port }) }) }) }) }) }) });
7769
+ }
7770
+ function LockedScreen({ lock }) {
7771
+ const [busy, setBusy] = (0, import_react41.useState)(false);
7772
+ const [error, setError] = (0, import_react41.useState)(null);
7773
+ const unlock = async () => {
7774
+ setBusy(true);
7775
+ setError(null);
7776
+ try {
7777
+ await lock.unlock();
7778
+ } catch (e) {
7779
+ setError(e instanceof Error && e.message ? e.message : "The vault stayed locked.");
7780
+ } finally {
7781
+ setBusy(false);
7782
+ }
7783
+ };
7784
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("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: [
7785
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LockGlyph, { className: "size-8 text-muted-foreground" }),
7786
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "text-base font-medium text-foreground", children: "Vault locked" }),
7787
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Button, { variant: "primary", disabled: busy, onClick: () => void unlock(), children: lock.unlockLabel ?? "Unlock" }),
7788
+ error ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { role: "alert", className: "max-w-sm text-sm text-destructive", children: error }) : null
7789
+ ] });
7696
7790
  }
7697
7791
  function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange }) {
7698
- const rootRef = (0, import_react40.useRef)(null);
7792
+ const rootRef = (0, import_react41.useRef)(null);
7699
7793
  const width = useElementWidth(rootRef);
7700
7794
  const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
7701
7795
  const notify = useNotify();
7702
- const [snap, setSnap] = (0, import_react40.useState)(null);
7703
- const [items, setItems] = (0, import_react40.useState)([]);
7704
- const [deleted, setDeleted] = (0, import_react40.useState)([]);
7705
- const [favorites, setFavorites] = (0, import_react40.useState)(null);
7706
- const [recents, setRecents] = (0, import_react40.useState)(null);
7707
- const [error, setError] = (0, import_react40.useState)(null);
7708
- const [inner, setInner] = (0, import_react40.useState)(DEFAULT_LOCATION);
7796
+ const [snap, setSnap] = (0, import_react41.useState)(null);
7797
+ const [items, setItems] = (0, import_react41.useState)([]);
7798
+ const [deleted, setDeleted] = (0, import_react41.useState)([]);
7799
+ const [favorites, setFavorites] = (0, import_react41.useState)(null);
7800
+ const [recents, setRecents] = (0, import_react41.useState)(null);
7801
+ const [error, setError] = (0, import_react41.useState)(null);
7802
+ const [inner, setInner] = (0, import_react41.useState)(DEFAULT_LOCATION);
7709
7803
  const loc = location ?? inner;
7710
- const dirty = (0, import_react40.useRef)(false);
7711
- const [notice, setNotice] = (0, import_react40.useState)(null);
7712
- const move = (0, import_react40.useCallback)(
7804
+ const dirty = (0, import_react41.useRef)(false);
7805
+ const [notice, setNotice] = (0, import_react41.useState)(null);
7806
+ const move = (0, import_react41.useCallback)(
7713
7807
  (next, how) => {
7714
7808
  if (!location) setInner(next);
7715
7809
  onLocationChange?.(next, how);
7716
7810
  },
7717
7811
  [location, onLocationChange]
7718
7812
  );
7719
- const go = (0, import_react40.useCallback)(
7813
+ const go = (0, import_react41.useCallback)(
7720
7814
  (patch, how = "push") => {
7721
7815
  const leaving = patch.itemId !== void 0 || patch.mode !== void 0 || patch.vault !== void 0 || patch.view !== void 0;
7722
7816
  const next = { ...loc, ...patch };
@@ -7735,9 +7829,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7735
7829
  },
7736
7830
  [loc, move]
7737
7831
  );
7738
- const knobsRef = (0, import_react40.useRef)(host.knobs);
7832
+ const knobsRef = (0, import_react41.useRef)(host.knobs);
7739
7833
  knobsRef.current = host.knobs;
7740
- const load = (0, import_react40.useCallback)(() => {
7834
+ const load = (0, import_react41.useCallback)(() => {
7741
7835
  setError(null);
7742
7836
  port.load().then((s) => {
7743
7837
  setSnap(s);
@@ -7752,17 +7846,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7752
7846
  knobsRef.current?.().catch(() => void 0);
7753
7847
  port.lists.recents?.list().then(setRecents, () => void 0);
7754
7848
  }, [port]);
7755
- (0, import_react40.useEffect)(load, [load]);
7756
- (0, import_react40.useEffect)(() => {
7849
+ (0, import_react41.useEffect)(load, [load]);
7850
+ (0, import_react41.useEffect)(() => {
7757
7851
  if (!loc.itemId || !port.lists.recents) return;
7758
7852
  const id = loc.itemId;
7759
7853
  port.lists.recents.record(id).then(() => setRecents((r) => [id, ...(r ?? []).filter((x) => x !== id)]), () => void 0);
7760
7854
  }, [loc.itemId, port]);
7761
7855
  const orgs = snap?.organizations ?? [];
7762
7856
  const definitions = snap?.definitions ?? [];
7763
- const inThisVault = (0, import_react40.useMemo)(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
7764
- const views = (0, import_react40.useMemo)(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
7765
- const visible = (0, import_react40.useMemo)(() => {
7857
+ const inThisVault = (0, import_react41.useMemo)(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
7858
+ const views = (0, import_react41.useMemo)(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
7859
+ const visible = (0, import_react41.useMemo)(() => {
7766
7860
  const filtered = inThisVault.filter((i) => {
7767
7861
  if (!matchesQuery(i, loc.q)) return false;
7768
7862
  if (loc.view === "favorites") return favorites?.has(i.id) ?? false;
@@ -7773,8 +7867,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7773
7867
  if (loc.view === "recent" && recents) return [...filtered].sort((a, b) => recents.indexOf(a.id) - recents.indexOf(b.id));
7774
7868
  return sortItems(filtered, loc.sort);
7775
7869
  }, [inThisVault, loc.view, loc.q, loc.sort, favorites, recents, definitions]);
7776
- const choices = (0, import_react40.useMemo)(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
7777
- const matchingIds = (0, import_react40.useMemo)(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
7870
+ const choices = (0, import_react41.useMemo)(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
7871
+ const matchingIds = (0, import_react41.useMemo)(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
7778
7872
  const selected = loc.itemId ? items.find((i) => i.id === loc.itemId) ?? null : null;
7779
7873
  const replaceItem = (next) => setItems((cur) => cur.some((i) => i.id === next.id) ? cur.map((i) => i.id === next.id ? next : i) : [...cur, next]);
7780
7874
  const toggleFavorite = (id) => {
@@ -7845,6 +7939,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7845
7939
  host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_design_system25.DropdownMenuItem, { onSelect: host.nativeProvider.openSetup, children: [
7846
7940
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ShieldGlyph, { className: "size-4" }),
7847
7941
  "System AutoFill"
7942
+ ] }) : null,
7943
+ host.lock?.lock ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_design_system25.DropdownMenuItem, { onSelect: () => void host.lock?.lock?.(), children: [
7944
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LockGlyph, { className: "size-4" }),
7945
+ "Lock"
7848
7946
  ] }) : null
7849
7947
  ] })
7850
7948
  ] })