@ai-matrx/vault 0.1.27 → 0.1.29
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 +20 -0
- package/dist/index.cjs +341 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -6
- package/dist/index.d.ts +47 -6
- package/dist/index.js +355 -94
- package/dist/index.js.map +1 -1
- package/dist/io/bitwarden-json.worker.js.map +1 -1
- package/package.json +4 -4
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 });
|
|
@@ -576,6 +581,17 @@ function useElementWidth(ref) {
|
|
|
576
581
|
}, [ref]);
|
|
577
582
|
return width;
|
|
578
583
|
}
|
|
584
|
+
function useDisposable(create, deps) {
|
|
585
|
+
const [held, setHeld] = useState3(null);
|
|
586
|
+
const make = useRef3(create);
|
|
587
|
+
make.current = create;
|
|
588
|
+
useEffect3(() => {
|
|
589
|
+
const made = make.current();
|
|
590
|
+
setHeld(made);
|
|
591
|
+
return () => made.dispose();
|
|
592
|
+
}, deps);
|
|
593
|
+
return held;
|
|
594
|
+
}
|
|
579
595
|
|
|
580
596
|
// src/ui.tsx
|
|
581
597
|
import { createContext as createContext4, useContext as useContext4, useEffect as useEffect4, useState as useState4 } from "react";
|
|
@@ -2637,9 +2653,12 @@ function normalizeLoginUrl(input) {
|
|
|
2637
2653
|
return null;
|
|
2638
2654
|
}
|
|
2639
2655
|
}
|
|
2656
|
+
function normalizeLoginUrls(inputs) {
|
|
2657
|
+
return inputs.map((u) => u.trim()).filter(Boolean).map((u) => normalizeLoginUrl(u) ?? u);
|
|
2658
|
+
}
|
|
2640
2659
|
function describeDestination(r) {
|
|
2641
2660
|
if (r.state === "reachable") return { url: r.normalizedUrl, state: r.state, tone: "success", message: "Website confirmed" };
|
|
2642
|
-
if (r.state === "invalid") return { url: r.normalizedUrl, state: r.state, tone: "
|
|
2661
|
+
if (r.state === "invalid") return { url: r.normalizedUrl, state: r.state, tone: "warning", message: "Not a public website. You can still save it." };
|
|
2643
2662
|
if (r.state === "not_found") return { url: r.normalizedUrl, state: r.state, tone: "warning", message: "Site answered, but this page was not found" };
|
|
2644
2663
|
return { url: r.normalizedUrl, state: r.state, tone: "warning", message: "Couldn\u2019t confirm it. You can still save it." };
|
|
2645
2664
|
}
|
|
@@ -3123,6 +3142,27 @@ function importLimitsFrom(resolved) {
|
|
|
3123
3142
|
return out;
|
|
3124
3143
|
}
|
|
3125
3144
|
|
|
3145
|
+
// src/knobs.ts
|
|
3146
|
+
import { createKnobReader } from "@ai-matrx/data/knobs";
|
|
3147
|
+
var FRESH_MS = 6e4;
|
|
3148
|
+
function createVaultKnobs(client, address) {
|
|
3149
|
+
const reader = createKnobReader(client);
|
|
3150
|
+
let kept = null;
|
|
3151
|
+
return async () => {
|
|
3152
|
+
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
3153
|
+
const snap = await reader.snapshot(address);
|
|
3154
|
+
kept = { at: Date.now(), resolved: snap.resolved };
|
|
3155
|
+
return snap.resolved;
|
|
3156
|
+
};
|
|
3157
|
+
}
|
|
3158
|
+
var REVEAL_SECONDS_KNOB = "desktop.vault.reveal_hide_seconds";
|
|
3159
|
+
var BACKUP_PASSPHRASE_MIN_KNOB = "desktop.vault.backup_passphrase_min_length";
|
|
3160
|
+
function positiveKnob(resolved, key) {
|
|
3161
|
+
const v = resolved[key];
|
|
3162
|
+
const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
|
|
3163
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3126
3166
|
// src/lock.ts
|
|
3127
3167
|
import { useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
3128
3168
|
var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
|
|
@@ -3318,7 +3358,8 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
|
|
|
3318
3358
|
/* @__PURE__ */ jsx17(VaultRow, { label: "Accept", hint: `${verb} without these`, children: /* @__PURE__ */ jsx17(Switch3, { checked: accepted, onCheckedChange: onAccepted, "aria-label": `${verb} without these` }) })
|
|
3319
3359
|
] });
|
|
3320
3360
|
}
|
|
3321
|
-
function BackupPanel({ port, items, onClose, onChanged }) {
|
|
3361
|
+
function BackupPanel({ port, host, items, onClose, onChanged }) {
|
|
3362
|
+
const minLength = passphraseMinimum(host.backupPassphraseMinLength);
|
|
3322
3363
|
const confirmed = useConfirmed();
|
|
3323
3364
|
const fileInput = useRef11(null);
|
|
3324
3365
|
const abort = useRef11(null);
|
|
@@ -3373,7 +3414,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3373
3414
|
setAccepted(false);
|
|
3374
3415
|
});
|
|
3375
3416
|
const downloadBackup = () => guarded(async () => {
|
|
3376
|
-
if (!backup) return;
|
|
3417
|
+
if (!backup || tooShort(passphrase, minLength)) return;
|
|
3377
3418
|
const bytes2 = await confirmed(() => port.io.downloadBackup({ itemIds: [...selected], revision: backup.revision, passphrase, acceptOmissions: accepted }));
|
|
3378
3419
|
downloadFile(BACKUP_FILENAME, bytes2, "application/octet-stream");
|
|
3379
3420
|
setPassphrase("");
|
|
@@ -3420,10 +3461,11 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3420
3461
|
};
|
|
3421
3462
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3422
3463
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3464
|
+
const short = passphrase !== "" && tooShort(passphrase, minLength);
|
|
3423
3465
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3424
3466
|
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3425
3467
|
/* @__PURE__ */ jsx17(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3426
|
-
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: [
|
|
3468
|
+
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: [
|
|
3427
3469
|
"Review ",
|
|
3428
3470
|
selected.size
|
|
3429
3471
|
] })
|
|
@@ -3470,7 +3512,14 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3470
3512
|
/* @__PURE__ */ jsx17(Summary, { value: backup }),
|
|
3471
3513
|
/* @__PURE__ */ jsx17(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3472
3514
|
/* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3473
|
-
/* @__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) }) }),
|
|
3515
|
+
/* @__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) }) }),
|
|
3516
|
+
short ? /* @__PURE__ */ jsxs16("p", { role: "alert", className: "px-1 text-xs text-destructive", "data-passphrase-too-short": "", children: [
|
|
3517
|
+
"Use at least ",
|
|
3518
|
+
minLength,
|
|
3519
|
+
" characters. This one has ",
|
|
3520
|
+
passphrase.length,
|
|
3521
|
+
"."
|
|
3522
|
+
] }) : null,
|
|
3474
3523
|
/* @__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) }) })
|
|
3475
3524
|
] })
|
|
3476
3525
|
] }) : null
|
|
@@ -3503,6 +3552,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3503
3552
|
/* @__PURE__ */ jsx17(ErrorLine, { message: error })
|
|
3504
3553
|
] });
|
|
3505
3554
|
}
|
|
3555
|
+
function passphraseMinimum(given) {
|
|
3556
|
+
return given !== void 0 && Number.isFinite(given) && given > 1 ? Math.floor(given) : null;
|
|
3557
|
+
}
|
|
3558
|
+
function tooShort(passphrase, minLength) {
|
|
3559
|
+
return minLength !== null && [...passphrase].length < minLength;
|
|
3560
|
+
}
|
|
3506
3561
|
|
|
3507
3562
|
// src/io/ExportPanel.tsx
|
|
3508
3563
|
import { useMemo, useState as useState18 } from "react";
|
|
@@ -5345,6 +5400,40 @@ function AssignResult({ sent, onAnother, onDone }) {
|
|
|
5345
5400
|
] });
|
|
5346
5401
|
}
|
|
5347
5402
|
|
|
5403
|
+
// src/lists/turn-back-on.ts
|
|
5404
|
+
async function turnBackOn(port, item, fields, options = {}) {
|
|
5405
|
+
const run = options.run ?? ((op) => op());
|
|
5406
|
+
const done = [];
|
|
5407
|
+
if (item.turnedOff) {
|
|
5408
|
+
await run(() => port.fields.updateItem(item, { active: true }));
|
|
5409
|
+
done.push("the item");
|
|
5410
|
+
}
|
|
5411
|
+
let n = 0;
|
|
5412
|
+
for (const f of fields) {
|
|
5413
|
+
if (f.active) continue;
|
|
5414
|
+
await run(() => port.fields.updateField(item, f.id, { active: true }));
|
|
5415
|
+
n += 1;
|
|
5416
|
+
}
|
|
5417
|
+
if (n) done.push(n === 1 ? "1 field" : `${n} fields`);
|
|
5418
|
+
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
5419
|
+
const codes = await port.authenticator.get(item);
|
|
5420
|
+
if (codes && !codes.enabled) {
|
|
5421
|
+
await run(() => port.authenticator.setEnabled(item, true));
|
|
5422
|
+
done.push("one-time codes");
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
if (options.browserFill && !item.browserFillEnabled && item.loginUrls.length > 0) {
|
|
5426
|
+
await run(() => port.fields.updateItem(item, { browserFillEnabled: true }));
|
|
5427
|
+
done.push("browser fill");
|
|
5428
|
+
}
|
|
5429
|
+
return done;
|
|
5430
|
+
}
|
|
5431
|
+
function turnedOnSentence(done) {
|
|
5432
|
+
if (done.length === 0) return "Nothing here was off.";
|
|
5433
|
+
const list = done.length === 1 ? done[0] : `${done.slice(0, -1).join(", ")} and ${done[done.length - 1]}`;
|
|
5434
|
+
return `Turned on ${list}.`;
|
|
5435
|
+
}
|
|
5436
|
+
|
|
5348
5437
|
// src/ItemPane.tsx
|
|
5349
5438
|
import { HistoryIcon, SettingsIcon, UsersIcon as UsersIcon2 } from "@ai-matrx/design-system/icons";
|
|
5350
5439
|
import { dropKeptDraft, keepDraft, readKeptDraft } from "@ai-matrx/kit/drafts";
|
|
@@ -5926,6 +6015,9 @@ import { Fragment as Fragment18, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-
|
|
|
5926
6015
|
var ENV_VALUE_KEY = "env_value";
|
|
5927
6016
|
var secureNoteDraft = () => ({ key: SECURE_NOTE_KEY, label: "Secure note", value: "", multiline: true, description: "Encrypted notes" });
|
|
5928
6017
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
6018
|
+
function confirmDelete(item) {
|
|
6019
|
+
return confirm10({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
|
|
6020
|
+
}
|
|
5929
6021
|
function ItemPane(props) {
|
|
5930
6022
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
5931
6023
|
const confirmed = useConfirmed();
|
|
@@ -5958,7 +6050,8 @@ function ItemPane(props) {
|
|
|
5958
6050
|
const [showBrowser, setShowBrowser] = useState27(false);
|
|
5959
6051
|
const [error, setError] = useState27(null);
|
|
5960
6052
|
const [destinations, setDestinations] = useState27({});
|
|
5961
|
-
const
|
|
6053
|
+
const [savedNew, setSavedNew] = useState27(false);
|
|
6054
|
+
const dirty = editing && !savedNew && isDirty(base, draft);
|
|
5962
6055
|
const declared = definition?.fields ?? [];
|
|
5963
6056
|
const prev = useRef14(null);
|
|
5964
6057
|
const paneRef = useRef14(null);
|
|
@@ -5981,8 +6074,11 @@ function ItemPane(props) {
|
|
|
5981
6074
|
setShowTags(false);
|
|
5982
6075
|
setShowDescription(false);
|
|
5983
6076
|
setShowRecovery(false);
|
|
6077
|
+
setSavedNew(false);
|
|
5984
6078
|
}, [item?.id, mode]);
|
|
5985
|
-
|
|
6079
|
+
const onDirtyRef = useRef14(onDirty);
|
|
6080
|
+
onDirtyRef.current = onDirty;
|
|
6081
|
+
useEffect16(() => onDirtyRef.current(dirty), [dirty]);
|
|
5986
6082
|
const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
|
|
5987
6083
|
useEffect16(() => {
|
|
5988
6084
|
if (editing && dirty) keepDraft(keepKey, keptFieldsOf(draft), { basedOn: item?.updatedAt ?? "new" });
|
|
@@ -6039,6 +6135,8 @@ function ItemPane(props) {
|
|
|
6039
6135
|
const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
|
|
6040
6136
|
const [next, n] = await storeQueuedFiles(withCode, n0);
|
|
6041
6137
|
dropKeptDraft(keepKey);
|
|
6138
|
+
setSavedNew(true);
|
|
6139
|
+
onDirty(false);
|
|
6042
6140
|
onSaved(next, true, n, enrolled);
|
|
6043
6141
|
}
|
|
6044
6142
|
} catch (e) {
|
|
@@ -6072,8 +6170,7 @@ function ItemPane(props) {
|
|
|
6072
6170
|
}
|
|
6073
6171
|
async function remove() {
|
|
6074
6172
|
if (!item) return;
|
|
6075
|
-
|
|
6076
|
-
if (!ok) return;
|
|
6173
|
+
if (!await confirmDelete(item)) return;
|
|
6077
6174
|
setBusy(true);
|
|
6078
6175
|
try {
|
|
6079
6176
|
await port.remove(item);
|
|
@@ -6101,12 +6198,7 @@ function ItemPane(props) {
|
|
|
6101
6198
|
if (!item) return;
|
|
6102
6199
|
setError(null);
|
|
6103
6200
|
try {
|
|
6104
|
-
|
|
6105
|
-
for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
|
|
6106
|
-
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
6107
|
-
const codes = await port.authenticator.get(item);
|
|
6108
|
-
if (codes && !codes.enabled) await confirmed(() => port.authenticator.setEnabled(item, true));
|
|
6109
|
-
}
|
|
6201
|
+
await turnBackOn(port, item, fields, { run: confirmed });
|
|
6110
6202
|
onChanged();
|
|
6111
6203
|
} catch (e) {
|
|
6112
6204
|
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
|
|
@@ -6161,7 +6253,7 @@ function ItemPane(props) {
|
|
|
6161
6253
|
"Unsaved"
|
|
6162
6254
|
] }) : null,
|
|
6163
6255
|
/* @__PURE__ */ jsx27(Button22, { variant: "quiet", disabled: busy, onClick: () => mode === "new" ? onCancelNew() : onMode("view"), children: dirty ? "Discard" : "Cancel" }),
|
|
6164
|
-
/* @__PURE__ */ jsx27(Button22, { variant: "primary", disabled: busy || sent !== null || draft.name.trim() === "" || mode === "edit" && !dirty || mode === "new" && owner === "person" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(recipient.trim()), onClick: () => void save(), children: mode === "new" && owner === "person" ? "Send" : "Save" })
|
|
6256
|
+
/* @__PURE__ */ jsx27(Button22, { variant: "primary", disabled: busy || savedNew || sent !== null || draft.name.trim() === "" || mode === "edit" && !dirty || mode === "new" && owner === "person" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(recipient.trim()), onClick: () => void save(), children: mode === "new" && owner === "person" ? "Send" : "Save" })
|
|
6165
6257
|
] }) : item ? /* @__PURE__ */ jsxs25("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
6166
6258
|
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ jsx27(UseOnSiteButton, { port, item, pageUrl: host.page.url, onChanged: (next) => onChanged(next) }) : null,
|
|
6167
6259
|
host.fill && item.capabilities.canUse ? /* @__PURE__ */ jsx27(
|
|
@@ -6329,7 +6421,8 @@ function ItemPane(props) {
|
|
|
6329
6421
|
else delete next[i];
|
|
6330
6422
|
return next;
|
|
6331
6423
|
});
|
|
6332
|
-
|
|
6424
|
+
const stored = r?.url || normalizeLoginUrl(u);
|
|
6425
|
+
if (stored && stored !== u) setDraft((d) => ({ ...d, loginUrls: d.loginUrls.map((x, j) => j === i && x === u ? stored : x) }));
|
|
6333
6426
|
}),
|
|
6334
6427
|
onRemove: () => patch({ loginUrls: draft.loginUrls.filter((_, j) => j !== i) }),
|
|
6335
6428
|
removeLabel: "Remove website"
|
|
@@ -6488,7 +6581,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6488
6581
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6489
6582
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6490
6583
|
}
|
|
6491
|
-
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 }) {
|
|
6584
|
+
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 }) {
|
|
6492
6585
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6493
6586
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6494
6587
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6509,7 +6602,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6509
6602
|
}
|
|
6510
6603
|
};
|
|
6511
6604
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6512
|
-
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);
|
|
6605
|
+
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);
|
|
6513
6606
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6514
6607
|
return /* @__PURE__ */ jsxs26("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6515
6608
|
/* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6553,7 +6646,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6553
6646
|
] }) })
|
|
6554
6647
|
] });
|
|
6555
6648
|
}
|
|
6556
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6649
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, onAction, favorite }) {
|
|
6557
6650
|
const confirmed = useConfirmed();
|
|
6558
6651
|
const copy = useCopy();
|
|
6559
6652
|
const notify = useNotify();
|
|
@@ -6594,11 +6687,12 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6594
6687
|
...favoriteEntry ? [favoriteEntry] : [],
|
|
6595
6688
|
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6596
6689
|
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6690
|
+
...manageEntries(item, onAction),
|
|
6597
6691
|
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6598
6692
|
];
|
|
6599
6693
|
const entriesRef = useRef15(entries);
|
|
6600
6694
|
entriesRef.current = entries;
|
|
6601
|
-
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" });
|
|
6695
|
+
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" });
|
|
6602
6696
|
const menuItem = (e) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6603
6697
|
glyphOf(e),
|
|
6604
6698
|
e.label
|
|
@@ -6652,6 +6746,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6652
6746
|
copyEntries.map(menuItem),
|
|
6653
6747
|
copyEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6654
6748
|
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6749
|
+
entries.some((e) => e.kind === "manage") ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6750
|
+
entries.filter((e) => e.kind === "manage").map(menuItem),
|
|
6655
6751
|
hostEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6656
6752
|
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6657
6753
|
] })
|
|
@@ -6661,6 +6757,17 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6661
6757
|
}
|
|
6662
6758
|
);
|
|
6663
6759
|
}
|
|
6760
|
+
function manageEntries(item, onAction) {
|
|
6761
|
+
if (!onAction) return [];
|
|
6762
|
+
const canManage = item.capabilities.canManage;
|
|
6763
|
+
const offManage = !canManage && manageUnavailableReason(item) !== null;
|
|
6764
|
+
const run = (action) => () => onAction(item, action);
|
|
6765
|
+
return [
|
|
6766
|
+
{ id: "activity", kind: "manage", label: "Activity", onSelect: run("activity") },
|
|
6767
|
+
...canManage || offManage ? [{ id: "share", kind: "manage", label: "Share", onSelect: run("share"), disabled: !canManage }] : [],
|
|
6768
|
+
...canManage || offManage ? [{ id: "delete", kind: "manage", label: "Delete", onSelect: run("delete"), disabled: !canManage }] : []
|
|
6769
|
+
];
|
|
6770
|
+
}
|
|
6664
6771
|
|
|
6665
6772
|
// src/lists/TrashView.tsx
|
|
6666
6773
|
import { useState as useState30 } from "react";
|
|
@@ -6741,8 +6848,16 @@ import { useEffect as useEffect18, useState as useState29 } from "react";
|
|
|
6741
6848
|
import { Button as Button24 } from "@ai-matrx/design-system/controls";
|
|
6742
6849
|
import { Fragment as Fragment19, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
6743
6850
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6744
|
-
function RestorePanel({
|
|
6851
|
+
function RestorePanel({
|
|
6852
|
+
lists,
|
|
6853
|
+
item,
|
|
6854
|
+
restore,
|
|
6855
|
+
turnOn,
|
|
6856
|
+
onClose
|
|
6857
|
+
}) {
|
|
6745
6858
|
const [preview, setPreview] = useState29(null);
|
|
6859
|
+
const [restored, setRestored] = useState29(null);
|
|
6860
|
+
const [turnedOn, setTurnedOn] = useState29(null);
|
|
6746
6861
|
const [error, setError] = useState29(null);
|
|
6747
6862
|
const [busy, setBusy] = useState29(false);
|
|
6748
6863
|
const [loading, setLoading] = useState29(Boolean(lists.preview));
|
|
@@ -6771,13 +6886,54 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6771
6886
|
setError(null);
|
|
6772
6887
|
try {
|
|
6773
6888
|
const result = await restore(preview?.supported ? preview.deletionId : void 0);
|
|
6774
|
-
if (result)
|
|
6889
|
+
if (!result) return;
|
|
6890
|
+
if (turnOn && !result.alreadyRestored && preview?.supported && !preview.priorWasDisabled) setRestored(result);
|
|
6891
|
+
else onClose();
|
|
6775
6892
|
} catch (e) {
|
|
6776
6893
|
setError(e instanceof Error && e.message ? e.message : "Restore did not complete. Try again.");
|
|
6777
6894
|
} finally {
|
|
6778
6895
|
setBusy(false);
|
|
6779
6896
|
}
|
|
6780
6897
|
};
|
|
6898
|
+
const runTurnOn = async () => {
|
|
6899
|
+
if (!restored || !turnOn) return;
|
|
6900
|
+
setBusy(true);
|
|
6901
|
+
setError(null);
|
|
6902
|
+
try {
|
|
6903
|
+
const said = await turnOn(restored.item);
|
|
6904
|
+
if (said !== null) setTurnedOn(said);
|
|
6905
|
+
} catch (e) {
|
|
6906
|
+
setError(e instanceof Error && e.message ? e.message : "It could not be turned on. Turn it on from the item.");
|
|
6907
|
+
} finally {
|
|
6908
|
+
setBusy(false);
|
|
6909
|
+
}
|
|
6910
|
+
};
|
|
6911
|
+
if (restored) {
|
|
6912
|
+
return /* @__PURE__ */ jsxs27(
|
|
6913
|
+
Panel,
|
|
6914
|
+
{
|
|
6915
|
+
title: `Restored "${item.name}"`,
|
|
6916
|
+
size: "md",
|
|
6917
|
+
onClose,
|
|
6918
|
+
footer: turnedOn ? /* @__PURE__ */ jsx29(Button24, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs27(Fragment19, { children: [
|
|
6919
|
+
/* @__PURE__ */ jsx29(Button24, { variant: "quiet", onClick: onClose, children: "Leave off" }),
|
|
6920
|
+
/* @__PURE__ */ jsx29(Button24, { variant: "primary", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busy, onClick: () => void runTurnOn(), children: busy ? "Turning on\u2026" : "Turn these back on" })
|
|
6921
|
+
] }),
|
|
6922
|
+
children: [
|
|
6923
|
+
/* @__PURE__ */ jsxs27(VaultSection, { title: turnedOn ? "Turned on" : "Back, turned off", children: [
|
|
6924
|
+
/* @__PURE__ */ jsx29(VaultRow, { label: "Came back", children: /* @__PURE__ */ jsxs27("span", { className: "text-foreground", children: [
|
|
6925
|
+
count(restored.restoredFields, "field"),
|
|
6926
|
+
", ",
|
|
6927
|
+
count(restored.restoredAttachments, "file")
|
|
6928
|
+
] }) }),
|
|
6929
|
+
turnedOn ? /* @__PURE__ */ jsx29(VaultRow, { label: "Now on", children: /* @__PURE__ */ jsx29("span", { role: "status", className: "text-foreground", children: turnedOn }) }) : /* @__PURE__ */ jsx29(VaultRow, { label: "Turns on", hint: "One press, nothing else changes", children: /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground", children: "The item, its fields, codes and browser fill" }) }),
|
|
6930
|
+
/* @__PURE__ */ jsx29(VaultRow, { label: "Stays off", hint: "Choose these again yourself", children: /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground", children: "Sharing, sandbox use" }) })
|
|
6931
|
+
] }),
|
|
6932
|
+
error ? /* @__PURE__ */ jsx29("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null
|
|
6933
|
+
]
|
|
6934
|
+
}
|
|
6935
|
+
);
|
|
6936
|
+
}
|
|
6781
6937
|
return /* @__PURE__ */ jsxs27(
|
|
6782
6938
|
Panel,
|
|
6783
6939
|
{
|
|
@@ -6818,7 +6974,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6818
6974
|
setMessage(null);
|
|
6819
6975
|
try {
|
|
6820
6976
|
const r = await confirmed(() => port.lists.restore(item, deletionId));
|
|
6821
|
-
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files
|
|
6977
|
+
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files, turned off.` });
|
|
6822
6978
|
onChanged();
|
|
6823
6979
|
return r;
|
|
6824
6980
|
} catch (e) {
|
|
@@ -6828,6 +6984,19 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6828
6984
|
setBusyId(null);
|
|
6829
6985
|
}
|
|
6830
6986
|
};
|
|
6987
|
+
const turnOn = async (item) => {
|
|
6988
|
+
try {
|
|
6989
|
+
const done = await turnBackOn(port, item, item.fields, { browserFill: true, run: confirmed });
|
|
6990
|
+
const said = turnedOnSentence(done);
|
|
6991
|
+
setMessage({ tone: "ok", text: `"${item.name}": ${said}` });
|
|
6992
|
+
onChanged();
|
|
6993
|
+
return said;
|
|
6994
|
+
} catch (e) {
|
|
6995
|
+
onChanged();
|
|
6996
|
+
if (wasCancelled(e)) return null;
|
|
6997
|
+
throw e;
|
|
6998
|
+
}
|
|
6999
|
+
};
|
|
6831
7000
|
return /* @__PURE__ */ jsxs28("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
|
|
6832
7001
|
header,
|
|
6833
7002
|
/* @__PURE__ */ jsx30(VaultSection, { title: "Trash", children: shown.length === 0 ? /* @__PURE__ */ jsx30(Empty, { children: deleted.length === 0 ? "The trash is empty." : "Nothing matches." }) : shown.map((item) => (
|
|
@@ -6841,7 +7010,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6841
7010
|
/* @__PURE__ */ jsx30(Button25, { variant: "outline", icon: /* @__PURE__ */ jsx30(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6842
7011
|
] }, item.id)
|
|
6843
7012
|
)) }),
|
|
6844
|
-
restoring ? /* @__PURE__ */ jsx30(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), onClose: () => setRestoring(null) }) : null,
|
|
7013
|
+
restoring ? /* @__PURE__ */ jsx30(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), turnOn, onClose: () => setRestoring(null) }) : null,
|
|
6845
7014
|
message2 ? /* @__PURE__ */ jsx30("p", { role: "status", className: message2.tone === "error" ? "px-1 text-sm text-destructive" : "px-1 text-sm text-muted-foreground", children: message2.text }) : null
|
|
6846
7015
|
] });
|
|
6847
7016
|
}
|
|
@@ -7806,7 +7975,7 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7806
7975
|
|
|
7807
7976
|
// src/extension/PageView.tsx
|
|
7808
7977
|
import { useState as useState39 } from "react";
|
|
7809
|
-
import {
|
|
7978
|
+
import { SiteIcon } from "@ai-matrx/design-system";
|
|
7810
7979
|
import { Button as Button33 } from "@ai-matrx/design-system/controls";
|
|
7811
7980
|
import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
7812
7981
|
|
|
@@ -8135,22 +8304,10 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
8135
8304
|
] })
|
|
8136
8305
|
] }),
|
|
8137
8306
|
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,
|
|
8307
|
+
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,
|
|
8138
8308
|
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,
|
|
8139
8309
|
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,
|
|
8140
|
-
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
|
|
8141
|
-
onSignIn ? /* @__PURE__ */ jsxs36(DropdownMenu5, { children: [
|
|
8142
|
-
/* @__PURE__ */ jsx38(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
|
|
8143
|
-
/* @__PURE__ */ jsxs36(DropdownMenuContent5, { align: "end", children: [
|
|
8144
|
-
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: onSignIn, children: [
|
|
8145
|
-
/* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4" }),
|
|
8146
|
-
"Sign me in"
|
|
8147
|
-
] }),
|
|
8148
|
-
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: () => onOpen(itemId), children: [
|
|
8149
|
-
/* @__PURE__ */ jsx38(ListGlyph, { className: "size-4" }),
|
|
8150
|
-
"Open item"
|
|
8151
|
-
] })
|
|
8152
|
-
] })
|
|
8153
|
-
] }) : null
|
|
8310
|
+
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
|
|
8154
8311
|
] });
|
|
8155
8312
|
}
|
|
8156
8313
|
|
|
@@ -8262,7 +8419,7 @@ function Group({ title, children }) {
|
|
|
8262
8419
|
children
|
|
8263
8420
|
] });
|
|
8264
8421
|
}
|
|
8265
|
-
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
8422
|
+
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
|
|
8266
8423
|
const [tagsOpen, setTagsOpen] = useState40(view.startsWith("tag:"));
|
|
8267
8424
|
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: [
|
|
8268
8425
|
/* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -8301,7 +8458,9 @@ function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, v
|
|
|
8301
8458
|
/* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4 shrink-0" }),
|
|
8302
8459
|
/* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
|
|
8303
8460
|
/* @__PURE__ */ jsx39("span", { className: cn15("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
|
|
8304
|
-
] }) : null
|
|
8461
|
+
] }) : null,
|
|
8462
|
+
onOpenWeb ? /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ExternalGlyph, label: "Open on the web", onClick: onOpenWeb }) : null,
|
|
8463
|
+
onLock ? /* @__PURE__ */ jsx39(Entry, { on: false, glyph: LockGlyph, label: "Lock", onClick: onLock }) : null
|
|
8305
8464
|
] })
|
|
8306
8465
|
] });
|
|
8307
8466
|
}
|
|
@@ -8344,12 +8503,42 @@ function ImportWithLimits(props) {
|
|
|
8344
8503
|
if (state && "limits" in state) return /* @__PURE__ */ jsx40(ImportPanel, { ...rest, limits: state.limits });
|
|
8345
8504
|
return /* @__PURE__ */ jsx40(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ jsx40(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
|
|
8346
8505
|
}
|
|
8347
|
-
function VaultApp(
|
|
8506
|
+
function VaultApp(given) {
|
|
8507
|
+
const props = { ...given, host: useOrganizationSettings(given.host ?? NO_HOST) };
|
|
8348
8508
|
const lock = props.host?.lock;
|
|
8349
8509
|
const locked = useLocked(lock);
|
|
8350
8510
|
const port = useMemo6(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
8351
8511
|
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 }) }) }) }) }) }) }) });
|
|
8352
8512
|
}
|
|
8513
|
+
function useOrganizationSettings(host) {
|
|
8514
|
+
const knobs = host.knobs;
|
|
8515
|
+
const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0);
|
|
8516
|
+
const [read, setRead] = useState41(null);
|
|
8517
|
+
useEffect23(() => {
|
|
8518
|
+
if (!needs || !knobs) return;
|
|
8519
|
+
let live = true;
|
|
8520
|
+
knobs().then(
|
|
8521
|
+
(r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB) }),
|
|
8522
|
+
() => void 0
|
|
8523
|
+
);
|
|
8524
|
+
return () => {
|
|
8525
|
+
live = false;
|
|
8526
|
+
};
|
|
8527
|
+
}, [needs, knobs]);
|
|
8528
|
+
if (!read) return host;
|
|
8529
|
+
return {
|
|
8530
|
+
...host,
|
|
8531
|
+
...host.revealSeconds === void 0 && read.reveal !== null ? { revealSeconds: read.reveal } : {},
|
|
8532
|
+
...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {}
|
|
8533
|
+
};
|
|
8534
|
+
}
|
|
8535
|
+
var NO_STORE = () => () => void 0;
|
|
8536
|
+
var NOTHING = () => null;
|
|
8537
|
+
function useHostPrompts(capture, fillSetup) {
|
|
8538
|
+
const prompt = useSyncExternalStore5(capture ? capture.subscribe : NO_STORE, capture ? capture.get : NOTHING, capture ? capture.get : NOTHING);
|
|
8539
|
+
const setup = useSyncExternalStore5(fillSetup ? fillSetup.subscribe : NO_STORE, fillSetup ? fillSetup.get : NOTHING, fillSetup ? fillSetup.get : NOTHING);
|
|
8540
|
+
return prompt !== null || setup?.status === "off";
|
|
8541
|
+
}
|
|
8353
8542
|
function LockedScreen({ lock }) {
|
|
8354
8543
|
const [busy, setBusy] = useState41(false);
|
|
8355
8544
|
const [error, setError] = useState41(null);
|
|
@@ -8437,6 +8626,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8437
8626
|
document.addEventListener("keydown", onKey);
|
|
8438
8627
|
return () => document.removeEventListener("keydown", onKey);
|
|
8439
8628
|
}, []);
|
|
8629
|
+
const keepSearchFocus = useRef19(false);
|
|
8630
|
+
useEffect23(() => {
|
|
8631
|
+
if (!keepSearchFocus.current) return;
|
|
8632
|
+
keepSearchFocus.current = false;
|
|
8633
|
+
const search = rootRef.current?.querySelector('input[aria-label^="Search"]');
|
|
8634
|
+
if (!search || document.activeElement === search) return;
|
|
8635
|
+
search.focus();
|
|
8636
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
8637
|
+
}, [loc.q]);
|
|
8638
|
+
const hasPrompts = useHostPrompts(host.capture, host.fillSetup);
|
|
8440
8639
|
const knobsRef = useRef19(host.knobs);
|
|
8441
8640
|
knobsRef.current = host.knobs;
|
|
8442
8641
|
const [signedOut, setSignedOut] = useState41(false);
|
|
@@ -8579,6 +8778,25 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8579
8778
|
notify(e instanceof Error ? e.message : "Favorites could not be saved.", "error");
|
|
8580
8779
|
});
|
|
8581
8780
|
};
|
|
8781
|
+
const deletedItem = (id) => {
|
|
8782
|
+
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8783
|
+
dirty.current = false;
|
|
8784
|
+
if (loc.itemId === id) move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8785
|
+
notify("Moved to Trash");
|
|
8786
|
+
load();
|
|
8787
|
+
};
|
|
8788
|
+
const rowAction = (item, action) => {
|
|
8789
|
+
if (action !== "delete") return go({ view: loc.view === "page" ? "all" : loc.view, itemId: item.id, mode: "view", panel: action });
|
|
8790
|
+
void confirmDelete(item).then(async (ok) => {
|
|
8791
|
+
if (!ok) return;
|
|
8792
|
+
try {
|
|
8793
|
+
await port.remove(item);
|
|
8794
|
+
deletedItem(item.id);
|
|
8795
|
+
} catch (e) {
|
|
8796
|
+
notify(e instanceof Error && e.message ? e.message : "Deleting failed.", "error");
|
|
8797
|
+
}
|
|
8798
|
+
});
|
|
8799
|
+
};
|
|
8582
8800
|
if (error) {
|
|
8583
8801
|
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: [
|
|
8584
8802
|
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
@@ -8617,38 +8835,38 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8617
8835
|
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null })
|
|
8618
8836
|
}
|
|
8619
8837
|
),
|
|
8620
|
-
/* @__PURE__ */ jsxs38(
|
|
8621
|
-
/* @__PURE__ */ jsx40(
|
|
8622
|
-
/* @__PURE__ */ jsxs38(
|
|
8623
|
-
/* @__PURE__ */ jsxs38(
|
|
8838
|
+
/* @__PURE__ */ jsxs38(DropdownMenu5, { children: [
|
|
8839
|
+
/* @__PURE__ */ jsx40(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx40(Button34, { variant: "quiet", icon: /* @__PURE__ */ jsx40(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8840
|
+
/* @__PURE__ */ jsxs38(DropdownMenuContent5, { align: "end", children: [
|
|
8841
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "import" }), children: [
|
|
8624
8842
|
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8625
8843
|
"Import"
|
|
8626
8844
|
] }),
|
|
8627
|
-
/* @__PURE__ */ jsxs38(
|
|
8845
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "export" }), children: [
|
|
8628
8846
|
/* @__PURE__ */ jsx40(ExportGlyph, { className: "size-4" }),
|
|
8629
8847
|
"Export"
|
|
8630
8848
|
] }),
|
|
8631
|
-
/* @__PURE__ */ jsxs38(
|
|
8849
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8632
8850
|
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-4" }),
|
|
8633
8851
|
"Backup"
|
|
8634
8852
|
] }),
|
|
8635
|
-
/* @__PURE__ */ jsxs38(
|
|
8853
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8636
8854
|
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8637
8855
|
"Browsers that fill"
|
|
8638
8856
|
] }),
|
|
8639
|
-
host.nativeImport ? /* @__PURE__ */ jsxs38(
|
|
8857
|
+
host.nativeImport ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8640
8858
|
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8641
8859
|
"Import passkeys"
|
|
8642
8860
|
] }) : null,
|
|
8643
|
-
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(
|
|
8861
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8644
8862
|
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8645
8863
|
"System AutoFill"
|
|
8646
8864
|
] }) : null,
|
|
8647
|
-
host.lock?.lock ? /* @__PURE__ */ jsxs38(
|
|
8865
|
+
host.lock?.lock ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8648
8866
|
/* @__PURE__ */ jsx40(LockGlyph, { className: "size-4" }),
|
|
8649
8867
|
"Lock"
|
|
8650
8868
|
] }) : null,
|
|
8651
|
-
host.openWebVault ? /* @__PURE__ */ jsxs38(
|
|
8869
|
+
host.openWebVault ? /* @__PURE__ */ jsxs38(DropdownMenuItem5, { onSelect: host.openWebVault, children: [
|
|
8652
8870
|
/* @__PURE__ */ jsx40(ExternalGlyph, { className: "size-4" }),
|
|
8653
8871
|
"Open on the web"
|
|
8654
8872
|
] }) : null
|
|
@@ -8662,6 +8880,27 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8662
8880
|
compactActions
|
|
8663
8881
|
] })
|
|
8664
8882
|
] });
|
|
8883
|
+
const newItem = () => go({ itemId: null, mode: "new", kind: null, panel: null });
|
|
8884
|
+
const pageHeader = /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", "data-vault-page-header": "", children: [
|
|
8885
|
+
compactHeader,
|
|
8886
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2", children: [
|
|
8887
|
+
/* @__PURE__ */ jsx40(
|
|
8888
|
+
SearchField4,
|
|
8889
|
+
{
|
|
8890
|
+
value: loc.q,
|
|
8891
|
+
onChange: (e) => {
|
|
8892
|
+
keepSearchFocus.current = true;
|
|
8893
|
+
go({ q: e.target.value }, "replace");
|
|
8894
|
+
},
|
|
8895
|
+
placeholder: "Search the vault",
|
|
8896
|
+
"aria-label": "Search the vault",
|
|
8897
|
+
className: "min-w-0 flex-1"
|
|
8898
|
+
}
|
|
8899
|
+
),
|
|
8900
|
+
compactActions,
|
|
8901
|
+
/* @__PURE__ */ jsx40(Button34, { variant: "primary", icon: /* @__PURE__ */ jsx40(PlusGlyph, {}), "aria-label": "New item", onClick: newItem })
|
|
8902
|
+
] })
|
|
8903
|
+
] });
|
|
8665
8904
|
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 };
|
|
8666
8905
|
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx40(
|
|
8667
8906
|
PageView,
|
|
@@ -8669,8 +8908,6 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8669
8908
|
port,
|
|
8670
8909
|
page: host.page,
|
|
8671
8910
|
fill: host.fill,
|
|
8672
|
-
capture: host.capture,
|
|
8673
|
-
fillSetup: host.fillSetup,
|
|
8674
8911
|
newPasswordFields: host.newPasswordFields,
|
|
8675
8912
|
items: inThisVault,
|
|
8676
8913
|
definitions,
|
|
@@ -8678,10 +8915,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8678
8915
|
onNewForPage: (url) => go({ mode: "new", kind: null, url, itemId: null, panel: null }),
|
|
8679
8916
|
onBrowse: () => go({ view: "all", itemId: null }),
|
|
8680
8917
|
onChanged: load,
|
|
8681
|
-
|
|
8682
|
-
compactHeader,
|
|
8683
|
-
/* @__PURE__ */ jsx40("div", { className: "flex justify-end", children: compactActions })
|
|
8684
|
-
] }) } : {}
|
|
8918
|
+
header: pageHeader
|
|
8685
8919
|
}
|
|
8686
8920
|
) : null;
|
|
8687
8921
|
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ jsx40(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ jsx40(TrashView, { ...viewProps }) : null);
|
|
@@ -8696,11 +8930,15 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8696
8930
|
selectedId: loc.itemId,
|
|
8697
8931
|
onSelect: (id) => go({ itemId: id, mode: "view", kind: null, panel: null }),
|
|
8698
8932
|
query: loc.q,
|
|
8699
|
-
onQuery: (q) =>
|
|
8933
|
+
onQuery: (q) => {
|
|
8934
|
+
if (loc.view === "page" && host.page && !q) keepSearchFocus.current = true;
|
|
8935
|
+
go({ q }, "replace");
|
|
8936
|
+
},
|
|
8700
8937
|
sort: loc.sort,
|
|
8701
8938
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8702
8939
|
canSortViewed: port.lists.recents !== void 0,
|
|
8703
|
-
onNew:
|
|
8940
|
+
onNew: newItem,
|
|
8941
|
+
onItemAction: rowAction,
|
|
8704
8942
|
onRefresh: refresh,
|
|
8705
8943
|
refreshing,
|
|
8706
8944
|
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
@@ -8775,13 +9013,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8775
9013
|
setNotice(n);
|
|
8776
9014
|
notify("Saved");
|
|
8777
9015
|
},
|
|
8778
|
-
onDeleted:
|
|
8779
|
-
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8780
|
-
dirty.current = false;
|
|
8781
|
-
move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8782
|
-
notify("Moved to Trash");
|
|
8783
|
-
load();
|
|
8784
|
-
},
|
|
9016
|
+
onDeleted: deletedItem,
|
|
8785
9017
|
onDirty: (d) => {
|
|
8786
9018
|
dirty.current = d;
|
|
8787
9019
|
},
|
|
@@ -8842,6 +9074,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8842
9074
|
/* @__PURE__ */ jsx40("span", { className: "min-w-0 flex-1 truncate text-warning", title: refreshError, children: "Couldn\u2019t refresh. Showing what was loaded." }),
|
|
8843
9075
|
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: refresh, children: "Try again" })
|
|
8844
9076
|
] }) : null,
|
|
9077
|
+
hasPrompts ? (
|
|
9078
|
+
// "Save this login?" and "Turn on filling" show above the list in every view, not only "This page".
|
|
9079
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-3 border-b border-border px-3 py-3", "data-vault-host-prompts": "", children: [
|
|
9080
|
+
host.fillSetup ? /* @__PURE__ */ jsx40(FillSetupCard, { fillSetup: host.fillSetup }) : null,
|
|
9081
|
+
host.capture ? /* @__PURE__ */ jsx40(CaptureCard, { capture: host.capture, onChanged: load }) : null
|
|
9082
|
+
] })
|
|
9083
|
+
) : null,
|
|
8845
9084
|
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: [
|
|
8846
9085
|
/* @__PURE__ */ jsxs38("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8847
9086
|
"Couldn\u2019t load ",
|
|
@@ -8867,7 +9106,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8867
9106
|
onPanel: (p) => go({ panel: p }),
|
|
8868
9107
|
nativeProvider: host.nativeProvider,
|
|
8869
9108
|
hasNativeImport: host.nativeImport !== void 0,
|
|
8870
|
-
hasPage: host.page !== void 0
|
|
9109
|
+
hasPage: host.page !== void 0,
|
|
9110
|
+
onLock: host.lock?.lock ? () => void host.lock?.lock?.() : void 0,
|
|
9111
|
+
onOpenWeb: host.openWebVault
|
|
8871
9112
|
}
|
|
8872
9113
|
) : null,
|
|
8873
9114
|
shown.list ? /* @__PURE__ */ jsx40("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
|
|
@@ -9106,7 +9347,7 @@ function createFieldsPort(ctx) {
|
|
|
9106
9347
|
const body = { initiation: "user" };
|
|
9107
9348
|
if (patch.uriMatchMode !== void 0) body.uri_match_mode = patch.uriMatchMode;
|
|
9108
9349
|
if (patch.browserFillEnabled !== void 0) body.browser_fill_enabled = patch.browserFillEnabled;
|
|
9109
|
-
if (patch.loginUrls !== void 0) body.login_urls = patch.loginUrls;
|
|
9350
|
+
if (patch.loginUrls !== void 0) body.login_urls = normalizeLoginUrls(patch.loginUrls);
|
|
9110
9351
|
if (patch.active !== void 0) body.status = patch.active ? "active" : "disabled";
|
|
9111
9352
|
await account3.updateItem(api, { path: { item_id: item.id }, body }, ctx.optsFor(item));
|
|
9112
9353
|
return reread(item);
|
|
@@ -9118,6 +9359,33 @@ function createFieldsPort(ctx) {
|
|
|
9118
9359
|
};
|
|
9119
9360
|
}
|
|
9120
9361
|
|
|
9362
|
+
// src/server-reasons.ts
|
|
9363
|
+
var GENERIC = [/please check your input/i, /^\s*request failed\s*\(\d+\)\s*$/i, /^\s*bad request\.?\s*$/i, /^\s*HTTP \d+\s*$/i];
|
|
9364
|
+
var isGeneric = (s) => GENERIC.some((re) => re.test(s));
|
|
9365
|
+
function cleanReason(detail) {
|
|
9366
|
+
const s = detail.replace(/^\s*validation error:\s*/i, "").replace(/^\s*value error,\s*/i, "").trim();
|
|
9367
|
+
return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
|
|
9368
|
+
}
|
|
9369
|
+
function serverReason(e) {
|
|
9370
|
+
if (!e || typeof e !== "object") return null;
|
|
9371
|
+
const { status, detail, message: message2 } = e;
|
|
9372
|
+
if (typeof status !== "number" || status < 400 || status >= 500) return null;
|
|
9373
|
+
if (typeof detail !== "string" || !detail.trim() || isGeneric(detail)) return null;
|
|
9374
|
+
const shown = typeof message2 === "string" ? message2 : "";
|
|
9375
|
+
if (shown && !isGeneric(shown)) return null;
|
|
9376
|
+
return cleanReason(detail);
|
|
9377
|
+
}
|
|
9378
|
+
function withReason(e) {
|
|
9379
|
+
const reason = serverReason(e);
|
|
9380
|
+
if (reason) Object.assign(e, { message: reason, userMessage: reason });
|
|
9381
|
+
return e;
|
|
9382
|
+
}
|
|
9383
|
+
function withServerReasons(api) {
|
|
9384
|
+
const wrapped = Object.create(api);
|
|
9385
|
+
wrapped.call = (...args) => api.call(...args).catch((e) => Promise.reject(withReason(e)));
|
|
9386
|
+
return wrapped;
|
|
9387
|
+
}
|
|
9388
|
+
|
|
9121
9389
|
// src/io/api.ts
|
|
9122
9390
|
import * as account4 from "@ai-matrx/api/account";
|
|
9123
9391
|
var orgOpts = (organizationId) => organizationId ? { organizationId } : void 0;
|
|
@@ -9390,7 +9658,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
9390
9658
|
definition_key: definition.key,
|
|
9391
9659
|
provider_key: definition.providerKey,
|
|
9392
9660
|
tags: draft.tags,
|
|
9393
|
-
login_urls: draft.loginUrls,
|
|
9661
|
+
login_urls: normalizeLoginUrls(draft.loginUrls),
|
|
9394
9662
|
notes: draft.notes || null,
|
|
9395
9663
|
generate_field_key: generateFieldKey,
|
|
9396
9664
|
initiation: "user",
|
|
@@ -9587,7 +9855,8 @@ async function retrying(run, tries = 3) {
|
|
|
9587
9855
|
}
|
|
9588
9856
|
}
|
|
9589
9857
|
}
|
|
9590
|
-
function createApiVaultPort(
|
|
9858
|
+
function createApiVaultPort(hostApi, options = {}) {
|
|
9859
|
+
const api = withServerReasons(hostApi);
|
|
9591
9860
|
let defs = /* @__PURE__ */ new Map();
|
|
9592
9861
|
let auth = /* @__PURE__ */ new Map();
|
|
9593
9862
|
let orgs = [];
|
|
@@ -9742,6 +10011,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9742
10011
|
const declared = definition.fields;
|
|
9743
10012
|
const encrypted = declared.filter((f) => f.storage === "encrypted" && (draft.values[f.key] ?? "") !== "");
|
|
9744
10013
|
const meta = declared.filter((f) => f.storage === "metadata" && (draft.values[f.key] ?? "") !== "");
|
|
10014
|
+
const loginUrls = normalizeLoginUrls(draft.loginUrls);
|
|
9745
10015
|
const w = await account9.createItem(api, {
|
|
9746
10016
|
body: {
|
|
9747
10017
|
display_name: draft.name.trim(),
|
|
@@ -9749,10 +10019,10 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9749
10019
|
definition_key: definition.key,
|
|
9750
10020
|
provider_key: definition.providerKey,
|
|
9751
10021
|
tags: draft.tags,
|
|
9752
|
-
login_urls:
|
|
10022
|
+
login_urls: loginUrls,
|
|
9753
10023
|
// A login a person saves with its website is offered on that website (the server's own
|
|
9754
10024
|
// default is off, which made "Save a login" on a page answer "No saved login" there).
|
|
9755
|
-
...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } :
|
|
10025
|
+
...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } : loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
|
|
9756
10026
|
notes: draft.notes || null,
|
|
9757
10027
|
principal: organizationId ? { type: "organization", organization_id: organizationId } : { type: "user" },
|
|
9758
10028
|
initiation: "user",
|
|
@@ -9779,7 +10049,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9779
10049
|
else body.description = draft.description.trim();
|
|
9780
10050
|
}
|
|
9781
10051
|
if (JSON.stringify(draft.tags) !== JSON.stringify(item.tags)) body.tags = draft.tags;
|
|
9782
|
-
if (JSON.stringify(draft.loginUrls) !== JSON.stringify(item.loginUrls)) body.login_urls = draft.loginUrls;
|
|
10052
|
+
if (JSON.stringify(draft.loginUrls) !== JSON.stringify(item.loginUrls)) body.login_urls = normalizeLoginUrls(draft.loginUrls);
|
|
9783
10053
|
if (draft.notes !== item.notes) {
|
|
9784
10054
|
if (draft.notes === "") body.clear_notes = true;
|
|
9785
10055
|
else body.notes = draft.notes;
|
|
@@ -9811,20 +10081,6 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9811
10081
|
};
|
|
9812
10082
|
}
|
|
9813
10083
|
|
|
9814
|
-
// src/knobs.ts
|
|
9815
|
-
import { createKnobReader } from "@ai-matrx/data/knobs";
|
|
9816
|
-
var FRESH_MS = 6e4;
|
|
9817
|
-
function createVaultKnobs(client, address) {
|
|
9818
|
-
const reader = createKnobReader(client);
|
|
9819
|
-
let kept = null;
|
|
9820
|
-
return async () => {
|
|
9821
|
-
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
9822
|
-
const snap = await reader.snapshot(address);
|
|
9823
|
-
kept = { at: Date.now(), resolved: snap.resolved };
|
|
9824
|
-
return snap.resolved;
|
|
9825
|
-
};
|
|
9826
|
-
}
|
|
9827
|
-
|
|
9828
10084
|
// src/agent-context.ts
|
|
9829
10085
|
var hostOf = (url) => {
|
|
9830
10086
|
try {
|
|
@@ -9892,6 +10148,7 @@ function emptyReadAlarm(total, emptyIds, holdings) {
|
|
|
9892
10148
|
return `${staleAlarm(total)} (The check that tells an empty credential from an unreadable one did not answer either: ${holdings.why})`;
|
|
9893
10149
|
}
|
|
9894
10150
|
export {
|
|
10151
|
+
BACKUP_PASSPHRASE_MIN_KNOB,
|
|
9895
10152
|
CATEGORIES,
|
|
9896
10153
|
CONFIRM_RETURN_KEY,
|
|
9897
10154
|
DEFAULT_LOCATION,
|
|
@@ -9900,9 +10157,11 @@ export {
|
|
|
9900
10157
|
HOLDINGS_DOOR_MIGRATION,
|
|
9901
10158
|
IdentityGate,
|
|
9902
10159
|
LOCKED_MESSAGE,
|
|
10160
|
+
REVEAL_SECONDS_KNOB,
|
|
9903
10161
|
VaultApp,
|
|
9904
10162
|
VaultLockedError,
|
|
9905
10163
|
categoryOf,
|
|
10164
|
+
copiedLine,
|
|
9906
10165
|
copyValue,
|
|
9907
10166
|
createApiVaultPort,
|
|
9908
10167
|
createSupabaseIdentity,
|
|
@@ -9919,11 +10178,13 @@ export {
|
|
|
9919
10178
|
matchesQuery,
|
|
9920
10179
|
needsRecentSignIn,
|
|
9921
10180
|
parseDefinitions,
|
|
10181
|
+
positiveKnob,
|
|
9922
10182
|
providerOf,
|
|
9923
10183
|
rowMenuEntriesAt,
|
|
9924
10184
|
siteDomainOf,
|
|
9925
10185
|
sortItems,
|
|
9926
10186
|
useConfirmed,
|
|
10187
|
+
useDisposable,
|
|
9927
10188
|
vaultInventoryScope,
|
|
9928
10189
|
vaultItemFacts,
|
|
9929
10190
|
wasCancelled
|