@ai-matrx/vault 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/index.cjs +236 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -5
- package/dist/index.d.ts +46 -5
- package/dist/index.js +252 -118
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -101,8 +101,8 @@ var init_keepass_xml_worker_client = __esm({
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
// src/VaultApp.tsx
|
|
104
|
-
import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo6, useRef as useRef19, useState as useState41 } from "react";
|
|
105
|
-
import { DropdownMenu as
|
|
104
|
+
import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo6, useRef as useRef19, useState as useState41, useSyncExternalStore as useSyncExternalStore5 } from "react";
|
|
105
|
+
import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as DropdownMenuItem5, DropdownMenuTrigger as DropdownMenuTrigger5, LookScope } from "@ai-matrx/design-system";
|
|
106
106
|
import { Button as Button34, SearchField as SearchField4, Select as Select12 } from "@ai-matrx/design-system/controls";
|
|
107
107
|
import { confirm as confirm14 } from "@ai-matrx/kit/confirm-opener";
|
|
108
108
|
|
|
@@ -119,8 +119,8 @@ async function copyValue(text, label, options, deps) {
|
|
|
119
119
|
const secret = options.secret ?? true;
|
|
120
120
|
if (deps.clipboard) {
|
|
121
121
|
try {
|
|
122
|
-
await deps.clipboard.copy(text, { secret });
|
|
123
|
-
deps.notify(
|
|
122
|
+
const copied = await deps.clipboard.copy(text, { secret });
|
|
123
|
+
deps.notify(copiedLine(label, copied?.clearsAtMs ?? null), "success");
|
|
124
124
|
return true;
|
|
125
125
|
} catch (e) {
|
|
126
126
|
deps.notify(e instanceof Error && e.message ? e.message : `${label} could not be copied`, "error");
|
|
@@ -129,6 +129,11 @@ async function copyValue(text, label, options, deps) {
|
|
|
129
129
|
}
|
|
130
130
|
return copyText(text, { successMessage: `${label} copied`, failureMessage: `${label} could not be copied`, notify: (m, k) => deps.notify(m, k === "error" ? "error" : "success") });
|
|
131
131
|
}
|
|
132
|
+
function copiedLine(label, clearsAtMs) {
|
|
133
|
+
if (clearsAtMs === null || !Number.isFinite(clearsAtMs)) return `${label} copied`;
|
|
134
|
+
const at = new Date(clearsAtMs).toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
135
|
+
return `${label} copied. Clears at ${at}`;
|
|
136
|
+
}
|
|
132
137
|
var ClipboardCtx = createContext(void 0);
|
|
133
138
|
function ClipboardProvider({ clipboard, children }) {
|
|
134
139
|
return /* @__PURE__ */ jsx(ClipboardCtx.Provider, { value: clipboard, children });
|
|
@@ -210,7 +215,8 @@ import {
|
|
|
210
215
|
UploadIcon,
|
|
211
216
|
UserIcon,
|
|
212
217
|
UserRoundIcon,
|
|
213
|
-
XIcon
|
|
218
|
+
XIcon,
|
|
219
|
+
withGlyphDefaults
|
|
214
220
|
} from "@ai-matrx/design-system/icons";
|
|
215
221
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
216
222
|
function glyph(paths, air = [1, 1]) {
|
|
@@ -219,27 +225,29 @@ function glyph(paths, air = [1, 1]) {
|
|
|
219
225
|
return /* @__PURE__ */ jsx2("svg", { className, style, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: paths });
|
|
220
226
|
};
|
|
221
227
|
}
|
|
222
|
-
var KeyGlyph = KeyIcon;
|
|
223
|
-
var NoteGlyph = FileTextIcon;
|
|
224
|
-
var
|
|
225
|
-
var
|
|
226
|
-
var
|
|
227
|
-
var
|
|
228
|
-
var
|
|
229
|
-
var
|
|
230
|
-
var
|
|
231
|
-
var
|
|
232
|
-
var
|
|
233
|
-
var
|
|
234
|
-
var
|
|
235
|
-
var
|
|
236
|
-
var
|
|
237
|
-
var
|
|
238
|
-
var
|
|
239
|
-
var
|
|
240
|
-
var
|
|
241
|
-
var
|
|
242
|
-
var
|
|
228
|
+
var KeyGlyph = withGlyphDefaults(KeyIcon, {}, { air: [1, 2] });
|
|
229
|
+
var NoteGlyph = withGlyphDefaults(FileTextIcon, {}, { air: [3, 3] });
|
|
230
|
+
var CardGlyph = withGlyphDefaults(CreditCardIcon, {}, { air: [1, 1] });
|
|
231
|
+
var PersonGlyph = withGlyphDefaults(UserRoundIcon, {}, { air: [3, 3] });
|
|
232
|
+
var DatabaseGlyph = withGlyphDefaults(DatabaseIcon, {}, { air: [2, 2] });
|
|
233
|
+
var ServerGlyph = withGlyphDefaults(ServerIcon, {}, { air: [1, 1] });
|
|
234
|
+
var TerminalGlyph = withGlyphDefaults(TerminalIcon, {}, { air: [3, 3] });
|
|
235
|
+
var FileGlyph = withGlyphDefaults(FilePageIcon, {}, { air: [3, 3] });
|
|
236
|
+
var CodeGlyph = withGlyphDefaults(CodeIcon, {}, { air: [1, 1] });
|
|
237
|
+
var StarGlyph = withGlyphDefaults(StarIcon, {}, { air: [1, 1] });
|
|
238
|
+
var PlusGlyph = withGlyphDefaults(PlusIcon, {}, { air: [4, 4] });
|
|
239
|
+
var EyeGlyph = withGlyphDefaults(EyeIcon, {}, { air: [1, 1] });
|
|
240
|
+
var EyeOffGlyph = withGlyphDefaults(EyeOffIcon, {}, { air: [1, 1] });
|
|
241
|
+
var LockGlyph = withGlyphDefaults(LockIcon, {}, { air: [2, 2] });
|
|
242
|
+
var ExternalGlyph = withGlyphDefaults(ExternalLinkIcon, {}, { air: [2, 2] });
|
|
243
|
+
var TrashGlyph = withGlyphDefaults(TrashIcon, {}, { air: [2, 2] });
|
|
244
|
+
var ArchiveGlyph = withGlyphDefaults(ArchiveIcon, {}, { air: [1, 1] });
|
|
245
|
+
var TagGlyph = withGlyphDefaults(TagIcon, {}, { air: [1, 1] });
|
|
246
|
+
var ShieldGlyph = withGlyphDefaults(ShieldIcon, {}, { air: [3, 3] });
|
|
247
|
+
var BuildingGlyph = withGlyphDefaults(BuildingIcon, {}, { air: [3, 3] });
|
|
248
|
+
var ChevronLeftGlyph = withGlyphDefaults(ChevronLeftIcon, {}, { air: [8, 8] });
|
|
249
|
+
var GridGlyph = withGlyphDefaults(LayoutGridIcon, {}, { air: [2, 2] });
|
|
250
|
+
var PlugGlyph = withGlyphDefaults(PlugIcon, {}, { air: [5, 5] });
|
|
243
251
|
var FAMILY_GLYPHS = {
|
|
244
252
|
databases: DatabaseGlyph,
|
|
245
253
|
server_network: ServerGlyph,
|
|
@@ -253,34 +261,34 @@ function definitionGlyph(key, family) {
|
|
|
253
261
|
if (key === "username_password" || key === "website_login") return GlobeIcon;
|
|
254
262
|
return FAMILY_GLYPHS[family] ?? KeyGlyph;
|
|
255
263
|
}
|
|
256
|
-
var XGlyph = XIcon;
|
|
257
|
-
var PencilGlyph = PencilIcon;
|
|
258
|
-
var ClockGlyph = ClockIcon;
|
|
259
|
-
var MoreGlyph = MoreHorizontalIcon;
|
|
260
|
-
var ShareGlyph = ShareIcon;
|
|
261
|
-
var ListGlyph = ListIcon;
|
|
262
|
-
var ImportGlyph = DownloadIcon;
|
|
263
|
-
var ExportGlyph = UploadIcon;
|
|
264
|
-
var ChevronDownGlyph = ChevronDownIcon;
|
|
265
|
-
var ChevronRightGlyph = ChevronRightIcon;
|
|
266
|
-
var SortGlyph = ArrowUpDownIcon;
|
|
267
|
-
var UserGlyph = UserIcon;
|
|
268
|
-
var MoveGlyph = MoveIcon;
|
|
264
|
+
var XGlyph = withGlyphDefaults(XIcon, {}, { air: [5, 5] });
|
|
265
|
+
var PencilGlyph = withGlyphDefaults(PencilIcon, {}, { air: [2, 2] });
|
|
266
|
+
var ClockGlyph = withGlyphDefaults(ClockIcon, {}, { air: [1, 1] });
|
|
267
|
+
var MoreGlyph = withGlyphDefaults(MoreHorizontalIcon, {}, { air: [3, 3] });
|
|
268
|
+
var ShareGlyph = withGlyphDefaults(ShareIcon, {}, { air: [3, 3] });
|
|
269
|
+
var ListGlyph = withGlyphDefaults(ListIcon, {}, { air: [2, 2] });
|
|
270
|
+
var ImportGlyph = withGlyphDefaults(DownloadIcon, {}, { air: [2, 2] });
|
|
271
|
+
var ExportGlyph = withGlyphDefaults(UploadIcon, {}, { air: [2, 2] });
|
|
272
|
+
var ChevronDownGlyph = withGlyphDefaults(ChevronDownIcon, {}, { air: [5, 5] });
|
|
273
|
+
var ChevronRightGlyph = withGlyphDefaults(ChevronRightIcon, {}, { air: [8, 8] });
|
|
274
|
+
var SortGlyph = withGlyphDefaults(ArrowUpDownIcon, {}, { air: [2, 2] });
|
|
275
|
+
var UserGlyph = withGlyphDefaults(UserIcon, {}, { air: [5, 5] });
|
|
276
|
+
var MoveGlyph = withGlyphDefaults(MoveIcon, {}, { air: [1, 1] });
|
|
269
277
|
var SafeGlyph = glyph(/* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
270
278
|
/* @__PURE__ */ jsx2("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
271
279
|
/* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "4" }),
|
|
272
280
|
/* @__PURE__ */ jsx2("path", { d: "M12 8v1M12 15v1M8 12h1M15 12h1" })
|
|
273
281
|
] }), [2, 2]);
|
|
274
|
-
var RestoreGlyph = RotateCcwIcon;
|
|
275
|
-
var QrGlyph = QrCodeIcon;
|
|
276
|
-
var CameraGlyph = CameraIcon;
|
|
277
|
-
var CheckGlyph = CheckIcon;
|
|
278
|
-
var PowerGlyph = PowerIcon;
|
|
279
|
-
var RefreshGlyph = RefreshCwIcon;
|
|
280
|
-
var SlidersGlyph = SlidersVerticalIcon;
|
|
281
|
-
var UploadGlyph = UploadIcon;
|
|
282
|
-
var FingerprintGlyph = FingerprintPatternIcon;
|
|
283
|
-
var SendGlyph = SendIcon;
|
|
282
|
+
var RestoreGlyph = withGlyphDefaults(RotateCcwIcon, {}, { air: [2, 2] });
|
|
283
|
+
var QrGlyph = withGlyphDefaults(QrCodeIcon, {}, { air: [2, 2] });
|
|
284
|
+
var CameraGlyph = withGlyphDefaults(CameraIcon, {}, { air: [1, 1] });
|
|
285
|
+
var CheckGlyph = withGlyphDefaults(CheckIcon, {}, { air: [3, 3] });
|
|
286
|
+
var PowerGlyph = withGlyphDefaults(PowerIcon, {}, { air: [2, 2] });
|
|
287
|
+
var RefreshGlyph = withGlyphDefaults(RefreshCwIcon, {}, { air: [2, 2] });
|
|
288
|
+
var SlidersGlyph = withGlyphDefaults(SlidersVerticalIcon, {}, { air: [0, 0] });
|
|
289
|
+
var UploadGlyph = withGlyphDefaults(UploadIcon, {}, { air: [2, 2] });
|
|
290
|
+
var FingerprintGlyph = withGlyphDefaults(FingerprintPatternIcon, {}, { air: [1, 1] });
|
|
291
|
+
var SendGlyph = withGlyphDefaults(SendIcon, {}, { air: [1, 1] });
|
|
284
292
|
|
|
285
293
|
// src/auth/identity.ts
|
|
286
294
|
var CONFIRM_RETURN_KEY = "matrx-vault:confirming-as";
|
|
@@ -576,6 +584,17 @@ function useElementWidth(ref) {
|
|
|
576
584
|
}, [ref]);
|
|
577
585
|
return width;
|
|
578
586
|
}
|
|
587
|
+
function useDisposable(create, deps) {
|
|
588
|
+
const [held, setHeld] = useState3(null);
|
|
589
|
+
const make = useRef3(create);
|
|
590
|
+
make.current = create;
|
|
591
|
+
useEffect3(() => {
|
|
592
|
+
const made = make.current();
|
|
593
|
+
setHeld(made);
|
|
594
|
+
return () => made.dispose();
|
|
595
|
+
}, deps);
|
|
596
|
+
return held;
|
|
597
|
+
}
|
|
579
598
|
|
|
580
599
|
// src/ui.tsx
|
|
581
600
|
import { createContext as createContext4, useContext as useContext4, useEffect as useEffect4, useState as useState4 } from "react";
|
|
@@ -3126,6 +3145,27 @@ function importLimitsFrom(resolved) {
|
|
|
3126
3145
|
return out;
|
|
3127
3146
|
}
|
|
3128
3147
|
|
|
3148
|
+
// src/knobs.ts
|
|
3149
|
+
import { createKnobReader } from "@ai-matrx/data/knobs";
|
|
3150
|
+
var FRESH_MS = 6e4;
|
|
3151
|
+
function createVaultKnobs(client, address) {
|
|
3152
|
+
const reader = createKnobReader(client);
|
|
3153
|
+
let kept = null;
|
|
3154
|
+
return async () => {
|
|
3155
|
+
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
3156
|
+
const snap = await reader.snapshot(address);
|
|
3157
|
+
kept = { at: Date.now(), resolved: snap.resolved };
|
|
3158
|
+
return snap.resolved;
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3161
|
+
var REVEAL_SECONDS_KNOB = "desktop.vault.reveal_hide_seconds";
|
|
3162
|
+
var BACKUP_PASSPHRASE_MIN_KNOB = "desktop.vault.backup_passphrase_min_length";
|
|
3163
|
+
function positiveKnob(resolved, key) {
|
|
3164
|
+
const v = resolved[key];
|
|
3165
|
+
const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
|
|
3166
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3129
3169
|
// src/lock.ts
|
|
3130
3170
|
import { useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
3131
3171
|
var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
|
|
@@ -3321,7 +3361,8 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
|
|
|
3321
3361
|
/* @__PURE__ */ jsx17(VaultRow, { label: "Accept", hint: `${verb} without these`, children: /* @__PURE__ */ jsx17(Switch3, { checked: accepted, onCheckedChange: onAccepted, "aria-label": `${verb} without these` }) })
|
|
3322
3362
|
] });
|
|
3323
3363
|
}
|
|
3324
|
-
function BackupPanel({ port, items, onClose, onChanged }) {
|
|
3364
|
+
function BackupPanel({ port, host, items, onClose, onChanged }) {
|
|
3365
|
+
const minLength = passphraseMinimum(host.backupPassphraseMinLength);
|
|
3325
3366
|
const confirmed = useConfirmed();
|
|
3326
3367
|
const fileInput = useRef11(null);
|
|
3327
3368
|
const abort = useRef11(null);
|
|
@@ -3376,7 +3417,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3376
3417
|
setAccepted(false);
|
|
3377
3418
|
});
|
|
3378
3419
|
const downloadBackup = () => guarded(async () => {
|
|
3379
|
-
if (!backup) return;
|
|
3420
|
+
if (!backup || tooShort(passphrase, minLength)) return;
|
|
3380
3421
|
const bytes2 = await confirmed(() => port.io.downloadBackup({ itemIds: [...selected], revision: backup.revision, passphrase, acceptOmissions: accepted }));
|
|
3381
3422
|
downloadFile(BACKUP_FILENAME, bytes2, "application/octet-stream");
|
|
3382
3423
|
setPassphrase("");
|
|
@@ -3423,10 +3464,11 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3423
3464
|
};
|
|
3424
3465
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3425
3466
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3467
|
+
const short = passphrase !== "" && tooShort(passphrase, minLength);
|
|
3426
3468
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3427
3469
|
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3428
3470
|
/* @__PURE__ */ jsx17(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3429
|
-
backup ? /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy || !passphrase || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
|
|
3471
|
+
backup ? /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy || !passphrase || short || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
|
|
3430
3472
|
"Review ",
|
|
3431
3473
|
selected.size
|
|
3432
3474
|
] })
|
|
@@ -3473,7 +3515,14 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3473
3515
|
/* @__PURE__ */ jsx17(Summary, { value: backup }),
|
|
3474
3516
|
/* @__PURE__ */ jsx17(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3475
3517
|
/* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3476
|
-
/* @__PURE__ */ jsx17(VaultRow, { label: "Passphrase", hint: "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) }),
|
|
3518
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Passphrase", hint: minLength ? `At least ${minLength} characters. Not saved.` : "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", "aria-invalid": short || void 0, onChange: (e) => setPassphrase(e.target.value) }) }),
|
|
3519
|
+
short ? /* @__PURE__ */ jsxs16("p", { role: "alert", className: "px-1 text-xs text-destructive", "data-passphrase-too-short": "", children: [
|
|
3520
|
+
"Use at least ",
|
|
3521
|
+
minLength,
|
|
3522
|
+
" characters. This one has ",
|
|
3523
|
+
passphrase.length,
|
|
3524
|
+
"."
|
|
3525
|
+
] }) : null,
|
|
3477
3526
|
/* @__PURE__ */ jsx17(VaultRow, { label: "Repeat", ...mismatch ? { hint: "Doesn't match" } : {}, children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: repeat, autoComplete: "new-password", "aria-label": "Repeat the passphrase", onChange: (e) => setRepeat(e.target.value) }) })
|
|
3478
3527
|
] })
|
|
3479
3528
|
] }) : null
|
|
@@ -3506,6 +3555,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3506
3555
|
/* @__PURE__ */ jsx17(ErrorLine, { message: error })
|
|
3507
3556
|
] });
|
|
3508
3557
|
}
|
|
3558
|
+
function passphraseMinimum(given) {
|
|
3559
|
+
return given !== void 0 && Number.isFinite(given) && given > 1 ? Math.floor(given) : null;
|
|
3560
|
+
}
|
|
3561
|
+
function tooShort(passphrase, minLength) {
|
|
3562
|
+
return minLength !== null && [...passphrase].length < minLength;
|
|
3563
|
+
}
|
|
3509
3564
|
|
|
3510
3565
|
// src/io/ExportPanel.tsx
|
|
3511
3566
|
import { useMemo, useState as useState18 } from "react";
|
|
@@ -5963,6 +6018,9 @@ import { Fragment as Fragment18, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-
|
|
|
5963
6018
|
var ENV_VALUE_KEY = "env_value";
|
|
5964
6019
|
var secureNoteDraft = () => ({ key: SECURE_NOTE_KEY, label: "Secure note", value: "", multiline: true, description: "Encrypted notes" });
|
|
5965
6020
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
6021
|
+
function confirmDelete(item) {
|
|
6022
|
+
return confirm10({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
|
|
6023
|
+
}
|
|
5966
6024
|
function ItemPane(props) {
|
|
5967
6025
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
5968
6026
|
const confirmed = useConfirmed();
|
|
@@ -6115,8 +6173,7 @@ function ItemPane(props) {
|
|
|
6115
6173
|
}
|
|
6116
6174
|
async function remove() {
|
|
6117
6175
|
if (!item) return;
|
|
6118
|
-
|
|
6119
|
-
if (!ok) return;
|
|
6176
|
+
if (!await confirmDelete(item)) return;
|
|
6120
6177
|
setBusy(true);
|
|
6121
6178
|
try {
|
|
6122
6179
|
await port.remove(item);
|
|
@@ -6527,7 +6584,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6527
6584
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6528
6585
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6529
6586
|
}
|
|
6530
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, actions, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems, stillLoading, favorites, onToggleFavorite }) {
|
|
6587
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, actions, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems, stillLoading, favorites, onToggleFavorite, onItemAction }) {
|
|
6531
6588
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6532
6589
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6533
6590
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6548,7 +6605,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6548
6605
|
}
|
|
6549
6606
|
};
|
|
6550
6607
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6551
|
-
const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems, favorite: onToggleFavorite ? { on: favorites?.has(i.id) ?? false, toggle: () => onToggleFavorite(i.id) } : void 0 }, i.id);
|
|
6608
|
+
const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems, onAction: onItemAction, favorite: onToggleFavorite ? { on: favorites?.has(i.id) ?? false, toggle: () => onToggleFavorite(i.id) } : void 0 }, i.id);
|
|
6552
6609
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6553
6610
|
return /* @__PURE__ */ jsxs26("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6554
6611
|
/* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6592,7 +6649,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6592
6649
|
] }) })
|
|
6593
6650
|
] });
|
|
6594
6651
|
}
|
|
6595
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6652
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, onAction, favorite }) {
|
|
6596
6653
|
const confirmed = useConfirmed();
|
|
6597
6654
|
const copy = useCopy();
|
|
6598
6655
|
const notify = useNotify();
|
|
@@ -6633,11 +6690,12 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6633
6690
|
...favoriteEntry ? [favoriteEntry] : [],
|
|
6634
6691
|
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6635
6692
|
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6693
|
+
...manageEntries(item, onAction),
|
|
6636
6694
|
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6637
6695
|
];
|
|
6638
6696
|
const entriesRef = useRef15(entries);
|
|
6639
6697
|
entriesRef.current = entries;
|
|
6640
|
-
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ jsx28(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ jsx28(StarGlyph, { className: cn13("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" ? null : /* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" });
|
|
6698
|
+
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ jsx28(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ jsx28(StarGlyph, { className: cn13("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" || e.kind === "manage" ? null : /* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" });
|
|
6641
6699
|
const menuItem = (e) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6642
6700
|
glyphOf(e),
|
|
6643
6701
|
e.label
|
|
@@ -6691,6 +6749,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6691
6749
|
copyEntries.map(menuItem),
|
|
6692
6750
|
copyEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6693
6751
|
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6752
|
+
entries.some((e) => e.kind === "manage") ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6753
|
+
entries.filter((e) => e.kind === "manage").map(menuItem),
|
|
6694
6754
|
hostEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6695
6755
|
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6696
6756
|
] })
|
|
@@ -6700,6 +6760,17 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6700
6760
|
}
|
|
6701
6761
|
);
|
|
6702
6762
|
}
|
|
6763
|
+
function manageEntries(item, onAction) {
|
|
6764
|
+
if (!onAction) return [];
|
|
6765
|
+
const canManage = item.capabilities.canManage;
|
|
6766
|
+
const offManage = !canManage && manageUnavailableReason(item) !== null;
|
|
6767
|
+
const run = (action) => () => onAction(item, action);
|
|
6768
|
+
return [
|
|
6769
|
+
{ id: "activity", kind: "manage", label: "Activity", onSelect: run("activity") },
|
|
6770
|
+
...canManage || offManage ? [{ id: "share", kind: "manage", label: "Share", onSelect: run("share"), disabled: !canManage }] : [],
|
|
6771
|
+
...canManage || offManage ? [{ id: "delete", kind: "manage", label: "Delete", onSelect: run("delete"), disabled: !canManage }] : []
|
|
6772
|
+
];
|
|
6773
|
+
}
|
|
6703
6774
|
|
|
6704
6775
|
// src/lists/TrashView.tsx
|
|
6705
6776
|
import { useState as useState30 } from "react";
|
|
@@ -7907,7 +7978,7 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7907
7978
|
|
|
7908
7979
|
// src/extension/PageView.tsx
|
|
7909
7980
|
import { useState as useState39 } from "react";
|
|
7910
|
-
import {
|
|
7981
|
+
import { SiteIcon } from "@ai-matrx/design-system";
|
|
7911
7982
|
import { Button as Button33 } from "@ai-matrx/design-system/controls";
|
|
7912
7983
|
import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
7913
7984
|
|
|
@@ -8236,22 +8307,10 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
8236
8307
|
] })
|
|
8237
8308
|
] }),
|
|
8238
8309
|
onFill ? /* @__PURE__ */ jsx38(Button33, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
|
|
8310
|
+
onSignIn ? /* @__PURE__ */ jsx38(Button33, { variant: onFill ? "outline" : "primary", icon: /* @__PURE__ */ jsx38(ShieldGlyph, {}), disabled: busy, onClick: onSignIn, "aria-label": `Sign me in with ${item?.name ?? "this login"}`, title: "Sign me in", children: "Sign me in" }) : null,
|
|
8239
8311
|
user && item ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
|
|
8240
8312
|
secret && item ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
|
|
8241
|
-
otp ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(ClockGlyph, {}), "aria-label": "Copy one-time code", title: "Copy one-time code", disabled: reading, onClick: () => void read("One-time code", async () => (await port.authenticator.code(otp)).code) }) : null
|
|
8242
|
-
onSignIn ? /* @__PURE__ */ jsxs36(DropdownMenu5, { children: [
|
|
8243
|
-
/* @__PURE__ */ jsx38(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
|
|
8244
|
-
/* @__PURE__ */ jsxs36(DropdownMenuContent5, { align: "end", children: [
|
|
8245
|
-
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: onSignIn, children: [
|
|
8246
|
-
/* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4" }),
|
|
8247
|
-
"Sign me in"
|
|
8248
|
-
] }),
|
|
8249
|
-
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: () => onOpen(itemId), children: [
|
|
8250
|
-
/* @__PURE__ */ jsx38(ListGlyph, { className: "size-4" }),
|
|
8251
|
-
"Open item"
|
|
8252
|
-
] })
|
|
8253
|
-
] })
|
|
8254
|
-
] }) : null
|
|
8313
|
+
otp ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(ClockGlyph, {}), "aria-label": "Copy one-time code", title: "Copy one-time code", disabled: reading, onClick: () => void read("One-time code", async () => (await port.authenticator.code(otp)).code) }) : null
|
|
8255
8314
|
] });
|
|
8256
8315
|
}
|
|
8257
8316
|
|
|
@@ -8363,7 +8422,7 @@ function Group({ title, children }) {
|
|
|
8363
8422
|
children
|
|
8364
8423
|
] });
|
|
8365
8424
|
}
|
|
8366
|
-
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
8425
|
+
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
|
|
8367
8426
|
const [tagsOpen, setTagsOpen] = useState40(view.startsWith("tag:"));
|
|
8368
8427
|
return /* @__PURE__ */ jsxs37("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: [
|
|
8369
8428
|
/* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -8402,7 +8461,9 @@ function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, v
|
|
|
8402
8461
|
/* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4 shrink-0" }),
|
|
8403
8462
|
/* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
|
|
8404
8463
|
/* @__PURE__ */ jsx39("span", { className: cn15("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
|
|
8405
|
-
] }) : null
|
|
8464
|
+
] }) : null,
|
|
8465
|
+
onOpenWeb ? /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ExternalGlyph, label: "Open on the web", onClick: onOpenWeb }) : null,
|
|
8466
|
+
onLock ? /* @__PURE__ */ jsx39(Entry, { on: false, glyph: LockGlyph, label: "Lock", onClick: onLock }) : null
|
|
8406
8467
|
] })
|
|
8407
8468
|
] });
|
|
8408
8469
|
}
|
|
@@ -8445,12 +8506,42 @@ function ImportWithLimits(props) {
|
|
|
8445
8506
|
if (state && "limits" in state) return /* @__PURE__ */ jsx40(ImportPanel, { ...rest, limits: state.limits });
|
|
8446
8507
|
return /* @__PURE__ */ jsx40(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ jsx40(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
|
|
8447
8508
|
}
|
|
8448
|
-
function VaultApp(
|
|
8509
|
+
function VaultApp(given) {
|
|
8510
|
+
const props = { ...given, host: useOrganizationSettings(given.host ?? NO_HOST) };
|
|
8449
8511
|
const lock = props.host?.lock;
|
|
8450
8512
|
const locked = useLocked(lock);
|
|
8451
8513
|
const port = useMemo6(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
8452
8514
|
return /* @__PURE__ */ jsx40(LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ jsx40("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ jsx40(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ jsx40(LockedScreen, { lock }) : /* @__PURE__ */ jsx40(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ jsx40(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ jsx40(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ jsx40(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ jsx40(Workspace, { ...props, port }) }) }) }) }) }) }) });
|
|
8453
8515
|
}
|
|
8516
|
+
function useOrganizationSettings(host) {
|
|
8517
|
+
const knobs = host.knobs;
|
|
8518
|
+
const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0);
|
|
8519
|
+
const [read, setRead] = useState41(null);
|
|
8520
|
+
useEffect23(() => {
|
|
8521
|
+
if (!needs || !knobs) return;
|
|
8522
|
+
let live = true;
|
|
8523
|
+
knobs().then(
|
|
8524
|
+
(r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB) }),
|
|
8525
|
+
() => void 0
|
|
8526
|
+
);
|
|
8527
|
+
return () => {
|
|
8528
|
+
live = false;
|
|
8529
|
+
};
|
|
8530
|
+
}, [needs, knobs]);
|
|
8531
|
+
if (!read) return host;
|
|
8532
|
+
return {
|
|
8533
|
+
...host,
|
|
8534
|
+
...host.revealSeconds === void 0 && read.reveal !== null ? { revealSeconds: read.reveal } : {},
|
|
8535
|
+
...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {}
|
|
8536
|
+
};
|
|
8537
|
+
}
|
|
8538
|
+
var NO_STORE = () => () => void 0;
|
|
8539
|
+
var NOTHING = () => null;
|
|
8540
|
+
function useHostPrompts(capture, fillSetup) {
|
|
8541
|
+
const prompt = useSyncExternalStore5(capture ? capture.subscribe : NO_STORE, capture ? capture.get : NOTHING, capture ? capture.get : NOTHING);
|
|
8542
|
+
const setup = useSyncExternalStore5(fillSetup ? fillSetup.subscribe : NO_STORE, fillSetup ? fillSetup.get : NOTHING, fillSetup ? fillSetup.get : NOTHING);
|
|
8543
|
+
return prompt !== null || setup?.status === "off";
|
|
8544
|
+
}
|
|
8454
8545
|
function LockedScreen({ lock }) {
|
|
8455
8546
|
const [busy, setBusy] = useState41(false);
|
|
8456
8547
|
const [error, setError] = useState41(null);
|
|
@@ -8538,6 +8629,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8538
8629
|
document.addEventListener("keydown", onKey);
|
|
8539
8630
|
return () => document.removeEventListener("keydown", onKey);
|
|
8540
8631
|
}, []);
|
|
8632
|
+
const keepSearchFocus = useRef19(false);
|
|
8633
|
+
useEffect23(() => {
|
|
8634
|
+
if (!keepSearchFocus.current) return;
|
|
8635
|
+
keepSearchFocus.current = false;
|
|
8636
|
+
const search = rootRef.current?.querySelector('input[aria-label^="Search"]');
|
|
8637
|
+
if (!search || document.activeElement === search) return;
|
|
8638
|
+
search.focus();
|
|
8639
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
8640
|
+
}, [loc.q]);
|
|
8641
|
+
const hasPrompts = useHostPrompts(host.capture, host.fillSetup);
|
|
8541
8642
|
const knobsRef = useRef19(host.knobs);
|
|
8542
8643
|
knobsRef.current = host.knobs;
|
|
8543
8644
|
const [signedOut, setSignedOut] = useState41(false);
|
|
@@ -8680,6 +8781,25 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8680
8781
|
notify(e instanceof Error ? e.message : "Favorites could not be saved.", "error");
|
|
8681
8782
|
});
|
|
8682
8783
|
};
|
|
8784
|
+
const deletedItem = (id) => {
|
|
8785
|
+
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8786
|
+
dirty.current = false;
|
|
8787
|
+
if (loc.itemId === id) move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8788
|
+
notify("Moved to Trash");
|
|
8789
|
+
load();
|
|
8790
|
+
};
|
|
8791
|
+
const rowAction = (item, action) => {
|
|
8792
|
+
if (action !== "delete") return go({ view: loc.view === "page" ? "all" : loc.view, itemId: item.id, mode: "view", panel: action });
|
|
8793
|
+
void confirmDelete(item).then(async (ok) => {
|
|
8794
|
+
if (!ok) return;
|
|
8795
|
+
try {
|
|
8796
|
+
await port.remove(item);
|
|
8797
|
+
deletedItem(item.id);
|
|
8798
|
+
} catch (e) {
|
|
8799
|
+
notify(e instanceof Error && e.message ? e.message : "Deleting failed.", "error");
|
|
8800
|
+
}
|
|
8801
|
+
});
|
|
8802
|
+
};
|
|
8683
8803
|
if (error) {
|
|
8684
8804
|
return /* @__PURE__ */ jsxs38("div", { ref: rootRef, role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 bg-background p-6 text-center text-sm", children: [
|
|
8685
8805
|
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
@@ -8718,38 +8838,38 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8718
8838
|
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null })
|
|
8719
8839
|
}
|
|
8720
8840
|
),
|
|
8721
|
-
/* @__PURE__ */ jsxs38(
|
|
8722
|
-
/* @__PURE__ */ jsx40(
|
|
8723
|
-
/* @__PURE__ */ jsxs38(
|
|
8724
|
-
/* @__PURE__ */ jsxs38(
|
|
8841
|
+
/* @__PURE__ */ jsxs38(DropdownMenu5, { children: [
|
|
8842
|
+
/* @__PURE__ */ jsx40(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx40(Button34, { variant: "quiet", icon: /* @__PURE__ */ jsx40(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8843
|
+
/* @__PURE__ */ jsxs38(DropdownMenuContent5, { align: "end", children: [
|
|
8844
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "import" }), children: [
|
|
8725
8845
|
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8726
8846
|
"Import"
|
|
8727
8847
|
] }),
|
|
8728
|
-
/* @__PURE__ */ jsxs38(
|
|
8848
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "export" }), children: [
|
|
8729
8849
|
/* @__PURE__ */ jsx40(ExportGlyph, { className: "size-4" }),
|
|
8730
8850
|
"Export"
|
|
8731
8851
|
] }),
|
|
8732
|
-
/* @__PURE__ */ jsxs38(
|
|
8852
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8733
8853
|
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-4" }),
|
|
8734
8854
|
"Backup"
|
|
8735
8855
|
] }),
|
|
8736
|
-
/* @__PURE__ */ jsxs38(
|
|
8856
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8737
8857
|
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8738
8858
|
"Browsers that fill"
|
|
8739
8859
|
] }),
|
|
8740
|
-
host.nativeImport ? /* @__PURE__ */ jsxs38(
|
|
8860
|
+
host.nativeImport ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8741
8861
|
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8742
8862
|
"Import passkeys"
|
|
8743
8863
|
] }) : null,
|
|
8744
|
-
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(
|
|
8864
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8745
8865
|
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8746
8866
|
"System AutoFill"
|
|
8747
8867
|
] }) : null,
|
|
8748
|
-
host.lock?.lock ? /* @__PURE__ */ jsxs38(
|
|
8868
|
+
host.lock?.lock ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8749
8869
|
/* @__PURE__ */ jsx40(LockGlyph, { className: "size-4" }),
|
|
8750
8870
|
"Lock"
|
|
8751
8871
|
] }) : null,
|
|
8752
|
-
host.openWebVault ? /* @__PURE__ */ jsxs38(
|
|
8872
|
+
host.openWebVault ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: host.openWebVault, children: [
|
|
8753
8873
|
/* @__PURE__ */ jsx40(ExternalGlyph, { className: "size-4" }),
|
|
8754
8874
|
"Open on the web"
|
|
8755
8875
|
] }) : null
|
|
@@ -8763,6 +8883,27 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8763
8883
|
compactActions
|
|
8764
8884
|
] })
|
|
8765
8885
|
] });
|
|
8886
|
+
const newItem = () => go({ itemId: null, mode: "new", kind: null, panel: null });
|
|
8887
|
+
const pageHeader = /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", "data-vault-page-header": "", children: [
|
|
8888
|
+
compactHeader,
|
|
8889
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2", children: [
|
|
8890
|
+
/* @__PURE__ */ jsx40(
|
|
8891
|
+
SearchField4,
|
|
8892
|
+
{
|
|
8893
|
+
value: loc.q,
|
|
8894
|
+
onChange: (e) => {
|
|
8895
|
+
keepSearchFocus.current = true;
|
|
8896
|
+
go({ q: e.target.value }, "replace");
|
|
8897
|
+
},
|
|
8898
|
+
placeholder: "Search the vault",
|
|
8899
|
+
"aria-label": "Search the vault",
|
|
8900
|
+
className: "min-w-0 flex-1"
|
|
8901
|
+
}
|
|
8902
|
+
),
|
|
8903
|
+
compactActions,
|
|
8904
|
+
/* @__PURE__ */ jsx40(Button34, { variant: "primary", icon: /* @__PURE__ */ jsx40(PlusGlyph, {}), "aria-label": "New item", onClick: newItem })
|
|
8905
|
+
] })
|
|
8906
|
+
] });
|
|
8766
8907
|
const viewProps = { port, host, items: inThisVault, deleted, definitions, query: loc.q, onOpen: (id) => go({ view: "all", itemId: id, mode: "view", panel: null }), onChanged: load, header: viewHeader };
|
|
8767
8908
|
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx40(
|
|
8768
8909
|
PageView,
|
|
@@ -8770,8 +8911,6 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8770
8911
|
port,
|
|
8771
8912
|
page: host.page,
|
|
8772
8913
|
fill: host.fill,
|
|
8773
|
-
capture: host.capture,
|
|
8774
|
-
fillSetup: host.fillSetup,
|
|
8775
8914
|
newPasswordFields: host.newPasswordFields,
|
|
8776
8915
|
items: inThisVault,
|
|
8777
8916
|
definitions,
|
|
@@ -8779,10 +8918,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8779
8918
|
onNewForPage: (url) => go({ mode: "new", kind: null, url, itemId: null, panel: null }),
|
|
8780
8919
|
onBrowse: () => go({ view: "all", itemId: null }),
|
|
8781
8920
|
onChanged: load,
|
|
8782
|
-
|
|
8783
|
-
compactHeader,
|
|
8784
|
-
/* @__PURE__ */ jsx40("div", { className: "flex justify-end", children: compactActions })
|
|
8785
|
-
] }) } : {}
|
|
8921
|
+
header: pageHeader
|
|
8786
8922
|
}
|
|
8787
8923
|
) : null;
|
|
8788
8924
|
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ jsx40(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ jsx40(TrashView, { ...viewProps }) : null);
|
|
@@ -8797,11 +8933,15 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8797
8933
|
selectedId: loc.itemId,
|
|
8798
8934
|
onSelect: (id) => go({ itemId: id, mode: "view", kind: null, panel: null }),
|
|
8799
8935
|
query: loc.q,
|
|
8800
|
-
onQuery: (q) =>
|
|
8936
|
+
onQuery: (q) => {
|
|
8937
|
+
if (loc.view === "page" && host.page && !q) keepSearchFocus.current = true;
|
|
8938
|
+
go({ q }, "replace");
|
|
8939
|
+
},
|
|
8801
8940
|
sort: loc.sort,
|
|
8802
8941
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8803
8942
|
canSortViewed: port.lists.recents !== void 0,
|
|
8804
|
-
onNew:
|
|
8943
|
+
onNew: newItem,
|
|
8944
|
+
onItemAction: rowAction,
|
|
8805
8945
|
onRefresh: refresh,
|
|
8806
8946
|
refreshing,
|
|
8807
8947
|
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
@@ -8876,13 +9016,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8876
9016
|
setNotice(n);
|
|
8877
9017
|
notify("Saved");
|
|
8878
9018
|
},
|
|
8879
|
-
onDeleted:
|
|
8880
|
-
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8881
|
-
dirty.current = false;
|
|
8882
|
-
move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8883
|
-
notify("Moved to Trash");
|
|
8884
|
-
load();
|
|
8885
|
-
},
|
|
9019
|
+
onDeleted: deletedItem,
|
|
8886
9020
|
onDirty: (d) => {
|
|
8887
9021
|
dirty.current = d;
|
|
8888
9022
|
},
|
|
@@ -8943,6 +9077,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8943
9077
|
/* @__PURE__ */ jsx40("span", { className: "min-w-0 flex-1 truncate text-warning", title: refreshError, children: "Couldn\u2019t refresh. Showing what was loaded." }),
|
|
8944
9078
|
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: refresh, children: "Try again" })
|
|
8945
9079
|
] }) : null,
|
|
9080
|
+
hasPrompts ? (
|
|
9081
|
+
// "Save this login?" and "Turn on filling" show above the list in every view, not only "This page".
|
|
9082
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-3 border-b border-border px-3 py-3", "data-vault-host-prompts": "", children: [
|
|
9083
|
+
host.fillSetup ? /* @__PURE__ */ jsx40(FillSetupCard, { fillSetup: host.fillSetup }) : null,
|
|
9084
|
+
host.capture ? /* @__PURE__ */ jsx40(CaptureCard, { capture: host.capture, onChanged: load }) : null
|
|
9085
|
+
] })
|
|
9086
|
+
) : null,
|
|
8946
9087
|
snap.unavailable.length > 0 ? /* @__PURE__ */ jsxs38("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
|
|
8947
9088
|
/* @__PURE__ */ jsxs38("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8948
9089
|
"Couldn\u2019t load ",
|
|
@@ -8968,7 +9109,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8968
9109
|
onPanel: (p) => go({ panel: p }),
|
|
8969
9110
|
nativeProvider: host.nativeProvider,
|
|
8970
9111
|
hasNativeImport: host.nativeImport !== void 0,
|
|
8971
|
-
hasPage: host.page !== void 0
|
|
9112
|
+
hasPage: host.page !== void 0,
|
|
9113
|
+
onLock: host.lock?.lock ? () => void host.lock?.lock?.() : void 0,
|
|
9114
|
+
onOpenWeb: host.openWebVault
|
|
8972
9115
|
}
|
|
8973
9116
|
) : null,
|
|
8974
9117
|
shown.list ? /* @__PURE__ */ jsx40("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
|
|
@@ -9941,20 +10084,6 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
9941
10084
|
};
|
|
9942
10085
|
}
|
|
9943
10086
|
|
|
9944
|
-
// src/knobs.ts
|
|
9945
|
-
import { createKnobReader } from "@ai-matrx/data/knobs";
|
|
9946
|
-
var FRESH_MS = 6e4;
|
|
9947
|
-
function createVaultKnobs(client, address) {
|
|
9948
|
-
const reader = createKnobReader(client);
|
|
9949
|
-
let kept = null;
|
|
9950
|
-
return async () => {
|
|
9951
|
-
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
9952
|
-
const snap = await reader.snapshot(address);
|
|
9953
|
-
kept = { at: Date.now(), resolved: snap.resolved };
|
|
9954
|
-
return snap.resolved;
|
|
9955
|
-
};
|
|
9956
|
-
}
|
|
9957
|
-
|
|
9958
10087
|
// src/agent-context.ts
|
|
9959
10088
|
var hostOf = (url) => {
|
|
9960
10089
|
try {
|
|
@@ -10022,6 +10151,7 @@ function emptyReadAlarm(total, emptyIds, holdings) {
|
|
|
10022
10151
|
return `${staleAlarm(total)} (The check that tells an empty credential from an unreadable one did not answer either: ${holdings.why})`;
|
|
10023
10152
|
}
|
|
10024
10153
|
export {
|
|
10154
|
+
BACKUP_PASSPHRASE_MIN_KNOB,
|
|
10025
10155
|
CATEGORIES,
|
|
10026
10156
|
CONFIRM_RETURN_KEY,
|
|
10027
10157
|
DEFAULT_LOCATION,
|
|
@@ -10030,9 +10160,11 @@ export {
|
|
|
10030
10160
|
HOLDINGS_DOOR_MIGRATION,
|
|
10031
10161
|
IdentityGate,
|
|
10032
10162
|
LOCKED_MESSAGE,
|
|
10163
|
+
REVEAL_SECONDS_KNOB,
|
|
10033
10164
|
VaultApp,
|
|
10034
10165
|
VaultLockedError,
|
|
10035
10166
|
categoryOf,
|
|
10167
|
+
copiedLine,
|
|
10036
10168
|
copyValue,
|
|
10037
10169
|
createApiVaultPort,
|
|
10038
10170
|
createSupabaseIdentity,
|
|
@@ -10049,11 +10181,13 @@ export {
|
|
|
10049
10181
|
matchesQuery,
|
|
10050
10182
|
needsRecentSignIn,
|
|
10051
10183
|
parseDefinitions,
|
|
10184
|
+
positiveKnob,
|
|
10052
10185
|
providerOf,
|
|
10053
10186
|
rowMenuEntriesAt,
|
|
10054
10187
|
siteDomainOf,
|
|
10055
10188
|
sortItems,
|
|
10056
10189
|
useConfirmed,
|
|
10190
|
+
useDisposable,
|
|
10057
10191
|
vaultInventoryScope,
|
|
10058
10192
|
vaultItemFacts,
|
|
10059
10193
|
wasCancelled
|