@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.cjs
CHANGED
|
@@ -135,6 +135,7 @@ var init_keepass_xml_worker_client = __esm({
|
|
|
135
135
|
// src/index.ts
|
|
136
136
|
var src_exports = {};
|
|
137
137
|
__export(src_exports, {
|
|
138
|
+
BACKUP_PASSPHRASE_MIN_KNOB: () => BACKUP_PASSPHRASE_MIN_KNOB,
|
|
138
139
|
CATEGORIES: () => CATEGORIES,
|
|
139
140
|
CONFIRM_RETURN_KEY: () => CONFIRM_RETURN_KEY,
|
|
140
141
|
DEFAULT_LOCATION: () => DEFAULT_LOCATION,
|
|
@@ -143,9 +144,11 @@ __export(src_exports, {
|
|
|
143
144
|
HOLDINGS_DOOR_MIGRATION: () => HOLDINGS_DOOR_MIGRATION,
|
|
144
145
|
IdentityGate: () => IdentityGate,
|
|
145
146
|
LOCKED_MESSAGE: () => LOCKED_MESSAGE,
|
|
147
|
+
REVEAL_SECONDS_KNOB: () => REVEAL_SECONDS_KNOB,
|
|
146
148
|
VaultApp: () => VaultApp,
|
|
147
149
|
VaultLockedError: () => VaultLockedError,
|
|
148
150
|
categoryOf: () => categoryOf,
|
|
151
|
+
copiedLine: () => copiedLine,
|
|
149
152
|
copyValue: () => copyValue,
|
|
150
153
|
createApiVaultPort: () => createApiVaultPort,
|
|
151
154
|
createSupabaseIdentity: () => createSupabaseIdentity,
|
|
@@ -162,11 +165,13 @@ __export(src_exports, {
|
|
|
162
165
|
matchesQuery: () => matchesQuery,
|
|
163
166
|
needsRecentSignIn: () => needsRecentSignIn,
|
|
164
167
|
parseDefinitions: () => parseDefinitions,
|
|
168
|
+
positiveKnob: () => positiveKnob,
|
|
165
169
|
providerOf: () => providerOf,
|
|
166
170
|
rowMenuEntriesAt: () => rowMenuEntriesAt,
|
|
167
171
|
siteDomainOf: () => siteDomainOf,
|
|
168
172
|
sortItems: () => sortItems,
|
|
169
173
|
useConfirmed: () => useConfirmed,
|
|
174
|
+
useDisposable: () => useDisposable,
|
|
170
175
|
vaultInventoryScope: () => vaultInventoryScope,
|
|
171
176
|
vaultItemFacts: () => vaultItemFacts,
|
|
172
177
|
wasCancelled: () => wasCancelled
|
|
@@ -192,8 +197,8 @@ async function copyValue(text, label, options, deps) {
|
|
|
192
197
|
const secret = options.secret ?? true;
|
|
193
198
|
if (deps.clipboard) {
|
|
194
199
|
try {
|
|
195
|
-
await deps.clipboard.copy(text, { secret });
|
|
196
|
-
deps.notify(
|
|
200
|
+
const copied = await deps.clipboard.copy(text, { secret });
|
|
201
|
+
deps.notify(copiedLine(label, copied?.clearsAtMs ?? null), "success");
|
|
197
202
|
return true;
|
|
198
203
|
} catch (e) {
|
|
199
204
|
deps.notify(e instanceof Error && e.message ? e.message : `${label} could not be copied`, "error");
|
|
@@ -202,6 +207,11 @@ async function copyValue(text, label, options, deps) {
|
|
|
202
207
|
}
|
|
203
208
|
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") });
|
|
204
209
|
}
|
|
210
|
+
function copiedLine(label, clearsAtMs) {
|
|
211
|
+
if (clearsAtMs === null || !Number.isFinite(clearsAtMs)) return `${label} copied`;
|
|
212
|
+
const at = new Date(clearsAtMs).toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
213
|
+
return `${label} copied. Clears at ${at}`;
|
|
214
|
+
}
|
|
205
215
|
var ClipboardCtx = (0, import_react.createContext)(void 0);
|
|
206
216
|
function ClipboardProvider({ clipboard, children }) {
|
|
207
217
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClipboardCtx.Provider, { value: clipboard, children });
|
|
@@ -245,27 +255,29 @@ function glyph(paths, air = [1, 1]) {
|
|
|
245
255
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className, style, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: paths });
|
|
246
256
|
};
|
|
247
257
|
}
|
|
248
|
-
var KeyGlyph = import_icons.KeyIcon;
|
|
249
|
-
var NoteGlyph = import_icons.FileTextIcon;
|
|
250
|
-
var
|
|
251
|
-
var
|
|
252
|
-
var
|
|
253
|
-
var
|
|
254
|
-
var
|
|
255
|
-
var
|
|
256
|
-
var
|
|
257
|
-
var
|
|
258
|
-
var
|
|
259
|
-
var
|
|
260
|
-
var
|
|
261
|
-
var
|
|
262
|
-
var
|
|
263
|
-
var
|
|
264
|
-
var
|
|
265
|
-
var
|
|
266
|
-
var
|
|
267
|
-
var
|
|
268
|
-
var
|
|
258
|
+
var KeyGlyph = (0, import_icons.withGlyphDefaults)(import_icons.KeyIcon, {}, { air: [1, 2] });
|
|
259
|
+
var NoteGlyph = (0, import_icons.withGlyphDefaults)(import_icons.FileTextIcon, {}, { air: [3, 3] });
|
|
260
|
+
var CardGlyph = (0, import_icons.withGlyphDefaults)(import_icons.CreditCardIcon, {}, { air: [1, 1] });
|
|
261
|
+
var PersonGlyph = (0, import_icons.withGlyphDefaults)(import_icons.UserRoundIcon, {}, { air: [3, 3] });
|
|
262
|
+
var DatabaseGlyph = (0, import_icons.withGlyphDefaults)(import_icons.DatabaseIcon, {}, { air: [2, 2] });
|
|
263
|
+
var ServerGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ServerIcon, {}, { air: [1, 1] });
|
|
264
|
+
var TerminalGlyph = (0, import_icons.withGlyphDefaults)(import_icons.TerminalIcon, {}, { air: [3, 3] });
|
|
265
|
+
var FileGlyph = (0, import_icons.withGlyphDefaults)(import_icons.FilePageIcon, {}, { air: [3, 3] });
|
|
266
|
+
var CodeGlyph = (0, import_icons.withGlyphDefaults)(import_icons.CodeIcon, {}, { air: [1, 1] });
|
|
267
|
+
var StarGlyph = (0, import_icons.withGlyphDefaults)(import_icons.StarIcon, {}, { air: [1, 1] });
|
|
268
|
+
var PlusGlyph = (0, import_icons.withGlyphDefaults)(import_icons.PlusIcon, {}, { air: [4, 4] });
|
|
269
|
+
var EyeGlyph = (0, import_icons.withGlyphDefaults)(import_icons.EyeIcon, {}, { air: [1, 1] });
|
|
270
|
+
var EyeOffGlyph = (0, import_icons.withGlyphDefaults)(import_icons.EyeOffIcon, {}, { air: [1, 1] });
|
|
271
|
+
var LockGlyph = (0, import_icons.withGlyphDefaults)(import_icons.LockIcon, {}, { air: [2, 2] });
|
|
272
|
+
var ExternalGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ExternalLinkIcon, {}, { air: [2, 2] });
|
|
273
|
+
var TrashGlyph = (0, import_icons.withGlyphDefaults)(import_icons.TrashIcon, {}, { air: [2, 2] });
|
|
274
|
+
var ArchiveGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ArchiveIcon, {}, { air: [1, 1] });
|
|
275
|
+
var TagGlyph = (0, import_icons.withGlyphDefaults)(import_icons.TagIcon, {}, { air: [1, 1] });
|
|
276
|
+
var ShieldGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ShieldIcon, {}, { air: [3, 3] });
|
|
277
|
+
var BuildingGlyph = (0, import_icons.withGlyphDefaults)(import_icons.BuildingIcon, {}, { air: [3, 3] });
|
|
278
|
+
var ChevronLeftGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ChevronLeftIcon, {}, { air: [8, 8] });
|
|
279
|
+
var GridGlyph = (0, import_icons.withGlyphDefaults)(import_icons.LayoutGridIcon, {}, { air: [2, 2] });
|
|
280
|
+
var PlugGlyph = (0, import_icons.withGlyphDefaults)(import_icons.PlugIcon, {}, { air: [5, 5] });
|
|
269
281
|
var FAMILY_GLYPHS = {
|
|
270
282
|
databases: DatabaseGlyph,
|
|
271
283
|
server_network: ServerGlyph,
|
|
@@ -279,34 +291,34 @@ function definitionGlyph(key, family) {
|
|
|
279
291
|
if (key === "username_password" || key === "website_login") return import_icons.GlobeIcon;
|
|
280
292
|
return FAMILY_GLYPHS[family] ?? KeyGlyph;
|
|
281
293
|
}
|
|
282
|
-
var XGlyph = import_icons.XIcon;
|
|
283
|
-
var PencilGlyph = import_icons.PencilIcon;
|
|
284
|
-
var ClockGlyph = import_icons.ClockIcon;
|
|
285
|
-
var MoreGlyph = import_icons.MoreHorizontalIcon;
|
|
286
|
-
var ShareGlyph = import_icons.ShareIcon;
|
|
287
|
-
var ListGlyph = import_icons.ListIcon;
|
|
288
|
-
var ImportGlyph = import_icons.DownloadIcon;
|
|
289
|
-
var ExportGlyph = import_icons.UploadIcon;
|
|
290
|
-
var ChevronDownGlyph = import_icons.ChevronDownIcon;
|
|
291
|
-
var ChevronRightGlyph = import_icons.ChevronRightIcon;
|
|
292
|
-
var SortGlyph = import_icons.ArrowUpDownIcon;
|
|
293
|
-
var UserGlyph = import_icons.UserIcon;
|
|
294
|
-
var MoveGlyph = import_icons.MoveIcon;
|
|
294
|
+
var XGlyph = (0, import_icons.withGlyphDefaults)(import_icons.XIcon, {}, { air: [5, 5] });
|
|
295
|
+
var PencilGlyph = (0, import_icons.withGlyphDefaults)(import_icons.PencilIcon, {}, { air: [2, 2] });
|
|
296
|
+
var ClockGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ClockIcon, {}, { air: [1, 1] });
|
|
297
|
+
var MoreGlyph = (0, import_icons.withGlyphDefaults)(import_icons.MoreHorizontalIcon, {}, { air: [3, 3] });
|
|
298
|
+
var ShareGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ShareIcon, {}, { air: [3, 3] });
|
|
299
|
+
var ListGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ListIcon, {}, { air: [2, 2] });
|
|
300
|
+
var ImportGlyph = (0, import_icons.withGlyphDefaults)(import_icons.DownloadIcon, {}, { air: [2, 2] });
|
|
301
|
+
var ExportGlyph = (0, import_icons.withGlyphDefaults)(import_icons.UploadIcon, {}, { air: [2, 2] });
|
|
302
|
+
var ChevronDownGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ChevronDownIcon, {}, { air: [5, 5] });
|
|
303
|
+
var ChevronRightGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ChevronRightIcon, {}, { air: [8, 8] });
|
|
304
|
+
var SortGlyph = (0, import_icons.withGlyphDefaults)(import_icons.ArrowUpDownIcon, {}, { air: [2, 2] });
|
|
305
|
+
var UserGlyph = (0, import_icons.withGlyphDefaults)(import_icons.UserIcon, {}, { air: [5, 5] });
|
|
306
|
+
var MoveGlyph = (0, import_icons.withGlyphDefaults)(import_icons.MoveIcon, {}, { air: [1, 1] });
|
|
295
307
|
var SafeGlyph = glyph(/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
296
308
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
297
309
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "4" }),
|
|
298
310
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 8v1M12 15v1M8 12h1M15 12h1" })
|
|
299
311
|
] }), [2, 2]);
|
|
300
|
-
var RestoreGlyph = import_icons.RotateCcwIcon;
|
|
301
|
-
var QrGlyph = import_icons.QrCodeIcon;
|
|
302
|
-
var CameraGlyph = import_icons.CameraIcon;
|
|
303
|
-
var CheckGlyph = import_icons.CheckIcon;
|
|
304
|
-
var PowerGlyph = import_icons.PowerIcon;
|
|
305
|
-
var RefreshGlyph = import_icons.RefreshCwIcon;
|
|
306
|
-
var SlidersGlyph = import_icons.SlidersVerticalIcon;
|
|
307
|
-
var UploadGlyph = import_icons.UploadIcon;
|
|
308
|
-
var FingerprintGlyph = import_icons.FingerprintPatternIcon;
|
|
309
|
-
var SendGlyph = import_icons.SendIcon;
|
|
312
|
+
var RestoreGlyph = (0, import_icons.withGlyphDefaults)(import_icons.RotateCcwIcon, {}, { air: [2, 2] });
|
|
313
|
+
var QrGlyph = (0, import_icons.withGlyphDefaults)(import_icons.QrCodeIcon, {}, { air: [2, 2] });
|
|
314
|
+
var CameraGlyph = (0, import_icons.withGlyphDefaults)(import_icons.CameraIcon, {}, { air: [1, 1] });
|
|
315
|
+
var CheckGlyph = (0, import_icons.withGlyphDefaults)(import_icons.CheckIcon, {}, { air: [3, 3] });
|
|
316
|
+
var PowerGlyph = (0, import_icons.withGlyphDefaults)(import_icons.PowerIcon, {}, { air: [2, 2] });
|
|
317
|
+
var RefreshGlyph = (0, import_icons.withGlyphDefaults)(import_icons.RefreshCwIcon, {}, { air: [2, 2] });
|
|
318
|
+
var SlidersGlyph = (0, import_icons.withGlyphDefaults)(import_icons.SlidersVerticalIcon, {}, { air: [0, 0] });
|
|
319
|
+
var UploadGlyph = (0, import_icons.withGlyphDefaults)(import_icons.UploadIcon, {}, { air: [2, 2] });
|
|
320
|
+
var FingerprintGlyph = (0, import_icons.withGlyphDefaults)(import_icons.FingerprintPatternIcon, {}, { air: [1, 1] });
|
|
321
|
+
var SendGlyph = (0, import_icons.withGlyphDefaults)(import_icons.SendIcon, {}, { air: [1, 1] });
|
|
310
322
|
|
|
311
323
|
// src/auth/identity.ts
|
|
312
324
|
var CONFIRM_RETURN_KEY = "matrx-vault:confirming-as";
|
|
@@ -602,6 +614,17 @@ function useElementWidth(ref) {
|
|
|
602
614
|
}, [ref]);
|
|
603
615
|
return width;
|
|
604
616
|
}
|
|
617
|
+
function useDisposable(create, deps) {
|
|
618
|
+
const [held, setHeld] = (0, import_react3.useState)(null);
|
|
619
|
+
const make = (0, import_react3.useRef)(create);
|
|
620
|
+
make.current = create;
|
|
621
|
+
(0, import_react3.useEffect)(() => {
|
|
622
|
+
const made = make.current();
|
|
623
|
+
setHeld(made);
|
|
624
|
+
return () => made.dispose();
|
|
625
|
+
}, deps);
|
|
626
|
+
return held;
|
|
627
|
+
}
|
|
605
628
|
|
|
606
629
|
// src/ui.tsx
|
|
607
630
|
var import_react4 = require("react");
|
|
@@ -3149,6 +3172,27 @@ function importLimitsFrom(resolved) {
|
|
|
3149
3172
|
return out;
|
|
3150
3173
|
}
|
|
3151
3174
|
|
|
3175
|
+
// src/knobs.ts
|
|
3176
|
+
var import_knobs = require("@ai-matrx/data/knobs");
|
|
3177
|
+
var FRESH_MS = 6e4;
|
|
3178
|
+
function createVaultKnobs(client, address) {
|
|
3179
|
+
const reader = (0, import_knobs.createKnobReader)(client);
|
|
3180
|
+
let kept = null;
|
|
3181
|
+
return async () => {
|
|
3182
|
+
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
3183
|
+
const snap = await reader.snapshot(address);
|
|
3184
|
+
kept = { at: Date.now(), resolved: snap.resolved };
|
|
3185
|
+
return snap.resolved;
|
|
3186
|
+
};
|
|
3187
|
+
}
|
|
3188
|
+
var REVEAL_SECONDS_KNOB = "desktop.vault.reveal_hide_seconds";
|
|
3189
|
+
var BACKUP_PASSPHRASE_MIN_KNOB = "desktop.vault.backup_passphrase_min_length";
|
|
3190
|
+
function positiveKnob(resolved, key) {
|
|
3191
|
+
const v = resolved[key];
|
|
3192
|
+
const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
|
|
3193
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3152
3196
|
// src/lock.ts
|
|
3153
3197
|
var import_react16 = require("react");
|
|
3154
3198
|
var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
|
|
@@ -3344,7 +3388,8 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
|
|
|
3344
3388
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Accept", hint: `${verb} without these`, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Switch, { checked: accepted, onCheckedChange: onAccepted, "aria-label": `${verb} without these` }) })
|
|
3345
3389
|
] });
|
|
3346
3390
|
}
|
|
3347
|
-
function BackupPanel({ port, items, onClose, onChanged }) {
|
|
3391
|
+
function BackupPanel({ port, host, items, onClose, onChanged }) {
|
|
3392
|
+
const minLength = passphraseMinimum(host.backupPassphraseMinLength);
|
|
3348
3393
|
const confirmed = useConfirmed();
|
|
3349
3394
|
const fileInput = (0, import_react18.useRef)(null);
|
|
3350
3395
|
const abort = (0, import_react18.useRef)(null);
|
|
@@ -3399,7 +3444,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3399
3444
|
setAccepted(false);
|
|
3400
3445
|
});
|
|
3401
3446
|
const downloadBackup = () => guarded(async () => {
|
|
3402
|
-
if (!backup) return;
|
|
3447
|
+
if (!backup || tooShort(passphrase, minLength)) return;
|
|
3403
3448
|
const bytes2 = await confirmed(() => port.io.downloadBackup({ itemIds: [...selected], revision: backup.revision, passphrase, acceptOmissions: accepted }));
|
|
3404
3449
|
(0, import_download.downloadFile)(BACKUP_FILENAME, bytes2, "application/octet-stream");
|
|
3405
3450
|
setPassphrase("");
|
|
@@ -3446,10 +3491,11 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3446
3491
|
};
|
|
3447
3492
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3448
3493
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3494
|
+
const short = passphrase !== "" && tooShort(passphrase, minLength);
|
|
3449
3495
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3450
3496
|
const footer = mode === "backup" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3451
3497
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3452
|
-
backup ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "primary", disabled: busy || !passphrase || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_controls13.Button, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
|
|
3498
|
+
backup ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "primary", disabled: busy || !passphrase || short || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_controls13.Button, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
|
|
3453
3499
|
"Review ",
|
|
3454
3500
|
selected.size
|
|
3455
3501
|
] })
|
|
@@ -3496,7 +3542,14 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3496
3542
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Summary, { value: backup }),
|
|
3497
3543
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3498
3544
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { children: [
|
|
3499
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Passphrase", hint: "Not saved. It can't be recovered.", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Field, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) }),
|
|
3545
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Passphrase", hint: minLength ? `At least ${minLength} characters. Not saved.` : "Not saved. It can't be recovered.", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Field, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", "aria-invalid": short || void 0, onChange: (e) => setPassphrase(e.target.value) }) }),
|
|
3546
|
+
short ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { role: "alert", className: "px-1 text-xs text-destructive", "data-passphrase-too-short": "", children: [
|
|
3547
|
+
"Use at least ",
|
|
3548
|
+
minLength,
|
|
3549
|
+
" characters. This one has ",
|
|
3550
|
+
passphrase.length,
|
|
3551
|
+
"."
|
|
3552
|
+
] }) : null,
|
|
3500
3553
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Repeat", ...mismatch ? { hint: "Doesn't match" } : {}, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Field, { type: "password", value: repeat, autoComplete: "new-password", "aria-label": "Repeat the passphrase", onChange: (e) => setRepeat(e.target.value) }) })
|
|
3501
3554
|
] })
|
|
3502
3555
|
] }) : null
|
|
@@ -3529,6 +3582,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3529
3582
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ErrorLine, { message: error })
|
|
3530
3583
|
] });
|
|
3531
3584
|
}
|
|
3585
|
+
function passphraseMinimum(given) {
|
|
3586
|
+
return given !== void 0 && Number.isFinite(given) && given > 1 ? Math.floor(given) : null;
|
|
3587
|
+
}
|
|
3588
|
+
function tooShort(passphrase, minLength) {
|
|
3589
|
+
return minLength !== null && [...passphrase].length < minLength;
|
|
3590
|
+
}
|
|
3532
3591
|
|
|
3533
3592
|
// src/io/ExportPanel.tsx
|
|
3534
3593
|
var import_react19 = require("react");
|
|
@@ -5986,6 +6045,9 @@ var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
|
5986
6045
|
var ENV_VALUE_KEY = "env_value";
|
|
5987
6046
|
var secureNoteDraft = () => ({ key: SECURE_NOTE_KEY, label: "Secure note", value: "", multiline: true, description: "Encrypted notes" });
|
|
5988
6047
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
6048
|
+
function confirmDelete(item) {
|
|
6049
|
+
return (0, import_confirm_opener10.confirm)({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
|
|
6050
|
+
}
|
|
5989
6051
|
function ItemPane(props) {
|
|
5990
6052
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
5991
6053
|
const confirmed = useConfirmed();
|
|
@@ -6138,8 +6200,7 @@ function ItemPane(props) {
|
|
|
6138
6200
|
}
|
|
6139
6201
|
async function remove() {
|
|
6140
6202
|
if (!item) return;
|
|
6141
|
-
|
|
6142
|
-
if (!ok) return;
|
|
6203
|
+
if (!await confirmDelete(item)) return;
|
|
6143
6204
|
setBusy(true);
|
|
6144
6205
|
try {
|
|
6145
6206
|
await port.remove(item);
|
|
@@ -6550,7 +6611,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6550
6611
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6551
6612
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6552
6613
|
}
|
|
6553
|
-
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 }) {
|
|
6614
|
+
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 }) {
|
|
6554
6615
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6555
6616
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6556
6617
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6571,7 +6632,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6571
6632
|
}
|
|
6572
6633
|
};
|
|
6573
6634
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6574
|
-
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(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);
|
|
6635
|
+
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(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);
|
|
6575
6636
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6576
6637
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6577
6638
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6615,7 +6676,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6615
6676
|
] }) })
|
|
6616
6677
|
] });
|
|
6617
6678
|
}
|
|
6618
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6679
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, onAction, favorite }) {
|
|
6619
6680
|
const confirmed = useConfirmed();
|
|
6620
6681
|
const copy = useCopy();
|
|
6621
6682
|
const notify = useNotify();
|
|
@@ -6656,11 +6717,12 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6656
6717
|
...favoriteEntry ? [favoriteEntry] : [],
|
|
6657
6718
|
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6658
6719
|
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6720
|
+
...manageEntries(item, onAction),
|
|
6659
6721
|
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6660
6722
|
];
|
|
6661
6723
|
const entriesRef = (0, import_react29.useRef)(entries);
|
|
6662
6724
|
entriesRef.current = entries;
|
|
6663
|
-
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StarGlyph, { className: (0, import_design_system20.cn)("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" ? null : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" });
|
|
6725
|
+
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StarGlyph, { className: (0, import_design_system20.cn)("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" || e.kind === "manage" ? null : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" });
|
|
6664
6726
|
const menuItem = (e) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6665
6727
|
glyphOf(e),
|
|
6666
6728
|
e.label
|
|
@@ -6714,6 +6776,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6714
6776
|
copyEntries.map(menuItem),
|
|
6715
6777
|
copyEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6716
6778
|
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6779
|
+
entries.some((e) => e.kind === "manage") ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6780
|
+
entries.filter((e) => e.kind === "manage").map(menuItem),
|
|
6717
6781
|
hostEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6718
6782
|
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6719
6783
|
] })
|
|
@@ -6723,6 +6787,17 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6723
6787
|
}
|
|
6724
6788
|
);
|
|
6725
6789
|
}
|
|
6790
|
+
function manageEntries(item, onAction) {
|
|
6791
|
+
if (!onAction) return [];
|
|
6792
|
+
const canManage = item.capabilities.canManage;
|
|
6793
|
+
const offManage = !canManage && manageUnavailableReason(item) !== null;
|
|
6794
|
+
const run = (action) => () => onAction(item, action);
|
|
6795
|
+
return [
|
|
6796
|
+
{ id: "activity", kind: "manage", label: "Activity", onSelect: run("activity") },
|
|
6797
|
+
...canManage || offManage ? [{ id: "share", kind: "manage", label: "Share", onSelect: run("share"), disabled: !canManage }] : [],
|
|
6798
|
+
...canManage || offManage ? [{ id: "delete", kind: "manage", label: "Delete", onSelect: run("delete"), disabled: !canManage }] : []
|
|
6799
|
+
];
|
|
6800
|
+
}
|
|
6726
6801
|
|
|
6727
6802
|
// src/lists/TrashView.tsx
|
|
6728
6803
|
var import_react31 = require("react");
|
|
@@ -8259,22 +8334,10 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
8259
8334
|
] })
|
|
8260
8335
|
] }),
|
|
8261
8336
|
onFill ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
|
|
8337
|
+
onSignIn ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: onFill ? "outline" : "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ShieldGlyph, {}), disabled: busy, onClick: onSignIn, "aria-label": `Sign me in with ${item?.name ?? "this login"}`, title: "Sign me in", children: "Sign me in" }) : null,
|
|
8262
8338
|
user && item ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
|
|
8263
8339
|
secret && item ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
|
|
8264
|
-
otp ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(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
|
|
8265
|
-
onSignIn ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenu, { children: [
|
|
8266
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system24.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
|
|
8267
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuContent, { align: "end", children: [
|
|
8268
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuItem, { onSelect: onSignIn, children: [
|
|
8269
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8270
|
-
"Sign me in"
|
|
8271
|
-
] }),
|
|
8272
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuItem, { onSelect: () => onOpen(itemId), children: [
|
|
8273
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ListGlyph, { className: "size-4" }),
|
|
8274
|
-
"Open item"
|
|
8275
|
-
] })
|
|
8276
|
-
] })
|
|
8277
|
-
] }) : null
|
|
8340
|
+
otp ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(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
|
|
8278
8341
|
] });
|
|
8279
8342
|
}
|
|
8280
8343
|
|
|
@@ -8386,7 +8449,7 @@ function Group({ title, children }) {
|
|
|
8386
8449
|
children
|
|
8387
8450
|
] });
|
|
8388
8451
|
}
|
|
8389
|
-
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
8452
|
+
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
|
|
8390
8453
|
const [tagsOpen, setTagsOpen] = (0, import_react41.useState)(view.startsWith("tag:"));
|
|
8391
8454
|
return /* @__PURE__ */ (0, import_jsx_runtime39.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: [
|
|
8392
8455
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -8425,7 +8488,9 @@ function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, v
|
|
|
8425
8488
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ShieldGlyph, { className: "size-4 shrink-0" }),
|
|
8426
8489
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
|
|
8427
8490
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: (0, import_design_system25.cn)("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
|
|
8428
|
-
] }) : null
|
|
8491
|
+
] }) : null,
|
|
8492
|
+
onOpenWeb ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: ExternalGlyph, label: "Open on the web", onClick: onOpenWeb }) : null,
|
|
8493
|
+
onLock ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: LockGlyph, label: "Lock", onClick: onLock }) : null
|
|
8429
8494
|
] })
|
|
8430
8495
|
] });
|
|
8431
8496
|
}
|
|
@@ -8468,12 +8533,42 @@ function ImportWithLimits(props) {
|
|
|
8468
8533
|
if (state && "limits" in state) return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportPanel, { ...rest, limits: state.limits });
|
|
8469
8534
|
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
|
|
8470
8535
|
}
|
|
8471
|
-
function VaultApp(
|
|
8536
|
+
function VaultApp(given) {
|
|
8537
|
+
const props = { ...given, host: useOrganizationSettings(given.host ?? NO_HOST) };
|
|
8472
8538
|
const lock = props.host?.lock;
|
|
8473
8539
|
const locked = useLocked(lock);
|
|
8474
8540
|
const port = (0, import_react42.useMemo)(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
8475
8541
|
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_design_system26.LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockedScreen, { lock }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Workspace, { ...props, port }) }) }) }) }) }) }) });
|
|
8476
8542
|
}
|
|
8543
|
+
function useOrganizationSettings(host) {
|
|
8544
|
+
const knobs = host.knobs;
|
|
8545
|
+
const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0);
|
|
8546
|
+
const [read, setRead] = (0, import_react42.useState)(null);
|
|
8547
|
+
(0, import_react42.useEffect)(() => {
|
|
8548
|
+
if (!needs || !knobs) return;
|
|
8549
|
+
let live = true;
|
|
8550
|
+
knobs().then(
|
|
8551
|
+
(r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB) }),
|
|
8552
|
+
() => void 0
|
|
8553
|
+
);
|
|
8554
|
+
return () => {
|
|
8555
|
+
live = false;
|
|
8556
|
+
};
|
|
8557
|
+
}, [needs, knobs]);
|
|
8558
|
+
if (!read) return host;
|
|
8559
|
+
return {
|
|
8560
|
+
...host,
|
|
8561
|
+
...host.revealSeconds === void 0 && read.reveal !== null ? { revealSeconds: read.reveal } : {},
|
|
8562
|
+
...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {}
|
|
8563
|
+
};
|
|
8564
|
+
}
|
|
8565
|
+
var NO_STORE = () => () => void 0;
|
|
8566
|
+
var NOTHING = () => null;
|
|
8567
|
+
function useHostPrompts(capture, fillSetup) {
|
|
8568
|
+
const prompt = (0, import_react42.useSyncExternalStore)(capture ? capture.subscribe : NO_STORE, capture ? capture.get : NOTHING, capture ? capture.get : NOTHING);
|
|
8569
|
+
const setup = (0, import_react42.useSyncExternalStore)(fillSetup ? fillSetup.subscribe : NO_STORE, fillSetup ? fillSetup.get : NOTHING, fillSetup ? fillSetup.get : NOTHING);
|
|
8570
|
+
return prompt !== null || setup?.status === "off";
|
|
8571
|
+
}
|
|
8477
8572
|
function LockedScreen({ lock }) {
|
|
8478
8573
|
const [busy, setBusy] = (0, import_react42.useState)(false);
|
|
8479
8574
|
const [error, setError] = (0, import_react42.useState)(null);
|
|
@@ -8561,6 +8656,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8561
8656
|
document.addEventListener("keydown", onKey);
|
|
8562
8657
|
return () => document.removeEventListener("keydown", onKey);
|
|
8563
8658
|
}, []);
|
|
8659
|
+
const keepSearchFocus = (0, import_react42.useRef)(false);
|
|
8660
|
+
(0, import_react42.useEffect)(() => {
|
|
8661
|
+
if (!keepSearchFocus.current) return;
|
|
8662
|
+
keepSearchFocus.current = false;
|
|
8663
|
+
const search = rootRef.current?.querySelector('input[aria-label^="Search"]');
|
|
8664
|
+
if (!search || document.activeElement === search) return;
|
|
8665
|
+
search.focus();
|
|
8666
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
8667
|
+
}, [loc.q]);
|
|
8668
|
+
const hasPrompts = useHostPrompts(host.capture, host.fillSetup);
|
|
8564
8669
|
const knobsRef = (0, import_react42.useRef)(host.knobs);
|
|
8565
8670
|
knobsRef.current = host.knobs;
|
|
8566
8671
|
const [signedOut, setSignedOut] = (0, import_react42.useState)(false);
|
|
@@ -8703,6 +8808,25 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8703
8808
|
notify(e instanceof Error ? e.message : "Favorites could not be saved.", "error");
|
|
8704
8809
|
});
|
|
8705
8810
|
};
|
|
8811
|
+
const deletedItem = (id) => {
|
|
8812
|
+
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8813
|
+
dirty.current = false;
|
|
8814
|
+
if (loc.itemId === id) move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8815
|
+
notify("Moved to Trash");
|
|
8816
|
+
load();
|
|
8817
|
+
};
|
|
8818
|
+
const rowAction = (item, action) => {
|
|
8819
|
+
if (action !== "delete") return go({ view: loc.view === "page" ? "all" : loc.view, itemId: item.id, mode: "view", panel: action });
|
|
8820
|
+
void confirmDelete(item).then(async (ok) => {
|
|
8821
|
+
if (!ok) return;
|
|
8822
|
+
try {
|
|
8823
|
+
await port.remove(item);
|
|
8824
|
+
deletedItem(item.id);
|
|
8825
|
+
} catch (e) {
|
|
8826
|
+
notify(e instanceof Error && e.message ? e.message : "Deleting failed.", "error");
|
|
8827
|
+
}
|
|
8828
|
+
});
|
|
8829
|
+
};
|
|
8706
8830
|
if (error) {
|
|
8707
8831
|
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("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: [
|
|
8708
8832
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
@@ -8786,6 +8910,27 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8786
8910
|
compactActions
|
|
8787
8911
|
] })
|
|
8788
8912
|
] });
|
|
8913
|
+
const newItem = () => go({ itemId: null, mode: "new", kind: null, panel: null });
|
|
8914
|
+
const pageHeader = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col gap-2", "data-vault-page-header": "", children: [
|
|
8915
|
+
compactHeader,
|
|
8916
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
8917
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8918
|
+
import_controls35.SearchField,
|
|
8919
|
+
{
|
|
8920
|
+
value: loc.q,
|
|
8921
|
+
onChange: (e) => {
|
|
8922
|
+
keepSearchFocus.current = true;
|
|
8923
|
+
go({ q: e.target.value }, "replace");
|
|
8924
|
+
},
|
|
8925
|
+
placeholder: "Search the vault",
|
|
8926
|
+
"aria-label": "Search the vault",
|
|
8927
|
+
className: "min-w-0 flex-1"
|
|
8928
|
+
}
|
|
8929
|
+
),
|
|
8930
|
+
compactActions,
|
|
8931
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(PlusGlyph, {}), "aria-label": "New item", onClick: newItem })
|
|
8932
|
+
] })
|
|
8933
|
+
] });
|
|
8789
8934
|
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 };
|
|
8790
8935
|
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8791
8936
|
PageView,
|
|
@@ -8793,8 +8938,6 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8793
8938
|
port,
|
|
8794
8939
|
page: host.page,
|
|
8795
8940
|
fill: host.fill,
|
|
8796
|
-
capture: host.capture,
|
|
8797
|
-
fillSetup: host.fillSetup,
|
|
8798
8941
|
newPasswordFields: host.newPasswordFields,
|
|
8799
8942
|
items: inThisVault,
|
|
8800
8943
|
definitions,
|
|
@@ -8802,10 +8945,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8802
8945
|
onNewForPage: (url) => go({ mode: "new", kind: null, url, itemId: null, panel: null }),
|
|
8803
8946
|
onBrowse: () => go({ view: "all", itemId: null }),
|
|
8804
8947
|
onChanged: load,
|
|
8805
|
-
|
|
8806
|
-
compactHeader,
|
|
8807
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex justify-end", children: compactActions })
|
|
8808
|
-
] }) } : {}
|
|
8948
|
+
header: pageHeader
|
|
8809
8949
|
}
|
|
8810
8950
|
) : null;
|
|
8811
8951
|
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TrashView, { ...viewProps }) : null);
|
|
@@ -8820,11 +8960,15 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8820
8960
|
selectedId: loc.itemId,
|
|
8821
8961
|
onSelect: (id) => go({ itemId: id, mode: "view", kind: null, panel: null }),
|
|
8822
8962
|
query: loc.q,
|
|
8823
|
-
onQuery: (q) =>
|
|
8963
|
+
onQuery: (q) => {
|
|
8964
|
+
if (loc.view === "page" && host.page && !q) keepSearchFocus.current = true;
|
|
8965
|
+
go({ q }, "replace");
|
|
8966
|
+
},
|
|
8824
8967
|
sort: loc.sort,
|
|
8825
8968
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8826
8969
|
canSortViewed: port.lists.recents !== void 0,
|
|
8827
|
-
onNew:
|
|
8970
|
+
onNew: newItem,
|
|
8971
|
+
onItemAction: rowAction,
|
|
8828
8972
|
onRefresh: refresh,
|
|
8829
8973
|
refreshing,
|
|
8830
8974
|
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
@@ -8899,13 +9043,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8899
9043
|
setNotice(n);
|
|
8900
9044
|
notify("Saved");
|
|
8901
9045
|
},
|
|
8902
|
-
onDeleted:
|
|
8903
|
-
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8904
|
-
dirty.current = false;
|
|
8905
|
-
move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8906
|
-
notify("Moved to Trash");
|
|
8907
|
-
load();
|
|
8908
|
-
},
|
|
9046
|
+
onDeleted: deletedItem,
|
|
8909
9047
|
onDirty: (d) => {
|
|
8910
9048
|
dirty.current = d;
|
|
8911
9049
|
},
|
|
@@ -8966,6 +9104,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8966
9104
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "min-w-0 flex-1 truncate text-warning", title: refreshError, children: "Couldn\u2019t refresh. Showing what was loaded." }),
|
|
8967
9105
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: refresh, children: "Try again" })
|
|
8968
9106
|
] }) : null,
|
|
9107
|
+
hasPrompts ? (
|
|
9108
|
+
// "Save this login?" and "Turn on filling" show above the list in every view, not only "This page".
|
|
9109
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col gap-3 border-b border-border px-3 py-3", "data-vault-host-prompts": "", children: [
|
|
9110
|
+
host.fillSetup ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(FillSetupCard, { fillSetup: host.fillSetup }) : null,
|
|
9111
|
+
host.capture ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CaptureCard, { capture: host.capture, onChanged: load }) : null
|
|
9112
|
+
] })
|
|
9113
|
+
) : null,
|
|
8969
9114
|
snap.unavailable.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
|
|
8970
9115
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8971
9116
|
"Couldn\u2019t load ",
|
|
@@ -8991,7 +9136,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8991
9136
|
onPanel: (p) => go({ panel: p }),
|
|
8992
9137
|
nativeProvider: host.nativeProvider,
|
|
8993
9138
|
hasNativeImport: host.nativeImport !== void 0,
|
|
8994
|
-
hasPage: host.page !== void 0
|
|
9139
|
+
hasPage: host.page !== void 0,
|
|
9140
|
+
onLock: host.lock?.lock ? () => void host.lock?.lock?.() : void 0,
|
|
9141
|
+
onOpenWeb: host.openWebVault
|
|
8995
9142
|
}
|
|
8996
9143
|
) : null,
|
|
8997
9144
|
shown.list ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
|
|
@@ -9964,20 +10111,6 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
9964
10111
|
};
|
|
9965
10112
|
}
|
|
9966
10113
|
|
|
9967
|
-
// src/knobs.ts
|
|
9968
|
-
var import_knobs = require("@ai-matrx/data/knobs");
|
|
9969
|
-
var FRESH_MS = 6e4;
|
|
9970
|
-
function createVaultKnobs(client, address) {
|
|
9971
|
-
const reader = (0, import_knobs.createKnobReader)(client);
|
|
9972
|
-
let kept = null;
|
|
9973
|
-
return async () => {
|
|
9974
|
-
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
9975
|
-
const snap = await reader.snapshot(address);
|
|
9976
|
-
kept = { at: Date.now(), resolved: snap.resolved };
|
|
9977
|
-
return snap.resolved;
|
|
9978
|
-
};
|
|
9979
|
-
}
|
|
9980
|
-
|
|
9981
10114
|
// src/agent-context.ts
|
|
9982
10115
|
var hostOf = (url) => {
|
|
9983
10116
|
try {
|