@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.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 });
|
|
@@ -602,6 +612,17 @@ function useElementWidth(ref) {
|
|
|
602
612
|
}, [ref]);
|
|
603
613
|
return width;
|
|
604
614
|
}
|
|
615
|
+
function useDisposable(create, deps) {
|
|
616
|
+
const [held, setHeld] = (0, import_react3.useState)(null);
|
|
617
|
+
const make = (0, import_react3.useRef)(create);
|
|
618
|
+
make.current = create;
|
|
619
|
+
(0, import_react3.useEffect)(() => {
|
|
620
|
+
const made = make.current();
|
|
621
|
+
setHeld(made);
|
|
622
|
+
return () => made.dispose();
|
|
623
|
+
}, deps);
|
|
624
|
+
return held;
|
|
625
|
+
}
|
|
605
626
|
|
|
606
627
|
// src/ui.tsx
|
|
607
628
|
var import_react4 = require("react");
|
|
@@ -2663,9 +2684,12 @@ function normalizeLoginUrl(input) {
|
|
|
2663
2684
|
return null;
|
|
2664
2685
|
}
|
|
2665
2686
|
}
|
|
2687
|
+
function normalizeLoginUrls(inputs) {
|
|
2688
|
+
return inputs.map((u) => u.trim()).filter(Boolean).map((u) => normalizeLoginUrl(u) ?? u);
|
|
2689
|
+
}
|
|
2666
2690
|
function describeDestination(r) {
|
|
2667
2691
|
if (r.state === "reachable") return { url: r.normalizedUrl, state: r.state, tone: "success", message: "Website confirmed" };
|
|
2668
|
-
if (r.state === "invalid") return { url: r.normalizedUrl, state: r.state, tone: "
|
|
2692
|
+
if (r.state === "invalid") return { url: r.normalizedUrl, state: r.state, tone: "warning", message: "Not a public website. You can still save it." };
|
|
2669
2693
|
if (r.state === "not_found") return { url: r.normalizedUrl, state: r.state, tone: "warning", message: "Site answered, but this page was not found" };
|
|
2670
2694
|
return { url: r.normalizedUrl, state: r.state, tone: "warning", message: "Couldn\u2019t confirm it. You can still save it." };
|
|
2671
2695
|
}
|
|
@@ -3146,6 +3170,27 @@ function importLimitsFrom(resolved) {
|
|
|
3146
3170
|
return out;
|
|
3147
3171
|
}
|
|
3148
3172
|
|
|
3173
|
+
// src/knobs.ts
|
|
3174
|
+
var import_knobs = require("@ai-matrx/data/knobs");
|
|
3175
|
+
var FRESH_MS = 6e4;
|
|
3176
|
+
function createVaultKnobs(client, address) {
|
|
3177
|
+
const reader = (0, import_knobs.createKnobReader)(client);
|
|
3178
|
+
let kept = null;
|
|
3179
|
+
return async () => {
|
|
3180
|
+
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
3181
|
+
const snap = await reader.snapshot(address);
|
|
3182
|
+
kept = { at: Date.now(), resolved: snap.resolved };
|
|
3183
|
+
return snap.resolved;
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
var REVEAL_SECONDS_KNOB = "desktop.vault.reveal_hide_seconds";
|
|
3187
|
+
var BACKUP_PASSPHRASE_MIN_KNOB = "desktop.vault.backup_passphrase_min_length";
|
|
3188
|
+
function positiveKnob(resolved, key) {
|
|
3189
|
+
const v = resolved[key];
|
|
3190
|
+
const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
|
|
3191
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3149
3194
|
// src/lock.ts
|
|
3150
3195
|
var import_react16 = require("react");
|
|
3151
3196
|
var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
|
|
@@ -3341,7 +3386,8 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
|
|
|
3341
3386
|
/* @__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` }) })
|
|
3342
3387
|
] });
|
|
3343
3388
|
}
|
|
3344
|
-
function BackupPanel({ port, items, onClose, onChanged }) {
|
|
3389
|
+
function BackupPanel({ port, host, items, onClose, onChanged }) {
|
|
3390
|
+
const minLength = passphraseMinimum(host.backupPassphraseMinLength);
|
|
3345
3391
|
const confirmed = useConfirmed();
|
|
3346
3392
|
const fileInput = (0, import_react18.useRef)(null);
|
|
3347
3393
|
const abort = (0, import_react18.useRef)(null);
|
|
@@ -3396,7 +3442,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3396
3442
|
setAccepted(false);
|
|
3397
3443
|
});
|
|
3398
3444
|
const downloadBackup = () => guarded(async () => {
|
|
3399
|
-
if (!backup) return;
|
|
3445
|
+
if (!backup || tooShort(passphrase, minLength)) return;
|
|
3400
3446
|
const bytes2 = await confirmed(() => port.io.downloadBackup({ itemIds: [...selected], revision: backup.revision, passphrase, acceptOmissions: accepted }));
|
|
3401
3447
|
(0, import_download.downloadFile)(BACKUP_FILENAME, bytes2, "application/octet-stream");
|
|
3402
3448
|
setPassphrase("");
|
|
@@ -3443,10 +3489,11 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3443
3489
|
};
|
|
3444
3490
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3445
3491
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3492
|
+
const short = passphrase !== "" && tooShort(passphrase, minLength);
|
|
3446
3493
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3447
3494
|
const footer = mode === "backup" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3448
3495
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3449
|
-
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: [
|
|
3496
|
+
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: [
|
|
3450
3497
|
"Review ",
|
|
3451
3498
|
selected.size
|
|
3452
3499
|
] })
|
|
@@ -3493,7 +3540,14 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3493
3540
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Summary, { value: backup }),
|
|
3494
3541
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3495
3542
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { children: [
|
|
3496
|
-
/* @__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) }) }),
|
|
3543
|
+
/* @__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) }) }),
|
|
3544
|
+
short ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { role: "alert", className: "px-1 text-xs text-destructive", "data-passphrase-too-short": "", children: [
|
|
3545
|
+
"Use at least ",
|
|
3546
|
+
minLength,
|
|
3547
|
+
" characters. This one has ",
|
|
3548
|
+
passphrase.length,
|
|
3549
|
+
"."
|
|
3550
|
+
] }) : null,
|
|
3497
3551
|
/* @__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) }) })
|
|
3498
3552
|
] })
|
|
3499
3553
|
] }) : null
|
|
@@ -3526,6 +3580,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3526
3580
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ErrorLine, { message: error })
|
|
3527
3581
|
] });
|
|
3528
3582
|
}
|
|
3583
|
+
function passphraseMinimum(given) {
|
|
3584
|
+
return given !== void 0 && Number.isFinite(given) && given > 1 ? Math.floor(given) : null;
|
|
3585
|
+
}
|
|
3586
|
+
function tooShort(passphrase, minLength) {
|
|
3587
|
+
return minLength !== null && [...passphrase].length < minLength;
|
|
3588
|
+
}
|
|
3529
3589
|
|
|
3530
3590
|
// src/io/ExportPanel.tsx
|
|
3531
3591
|
var import_react19 = require("react");
|
|
@@ -5368,6 +5428,40 @@ function AssignResult({ sent, onAnother, onDone }) {
|
|
|
5368
5428
|
] });
|
|
5369
5429
|
}
|
|
5370
5430
|
|
|
5431
|
+
// src/lists/turn-back-on.ts
|
|
5432
|
+
async function turnBackOn(port, item, fields, options = {}) {
|
|
5433
|
+
const run = options.run ?? ((op) => op());
|
|
5434
|
+
const done = [];
|
|
5435
|
+
if (item.turnedOff) {
|
|
5436
|
+
await run(() => port.fields.updateItem(item, { active: true }));
|
|
5437
|
+
done.push("the item");
|
|
5438
|
+
}
|
|
5439
|
+
let n = 0;
|
|
5440
|
+
for (const f of fields) {
|
|
5441
|
+
if (f.active) continue;
|
|
5442
|
+
await run(() => port.fields.updateField(item, f.id, { active: true }));
|
|
5443
|
+
n += 1;
|
|
5444
|
+
}
|
|
5445
|
+
if (n) done.push(n === 1 ? "1 field" : `${n} fields`);
|
|
5446
|
+
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
5447
|
+
const codes = await port.authenticator.get(item);
|
|
5448
|
+
if (codes && !codes.enabled) {
|
|
5449
|
+
await run(() => port.authenticator.setEnabled(item, true));
|
|
5450
|
+
done.push("one-time codes");
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5453
|
+
if (options.browserFill && !item.browserFillEnabled && item.loginUrls.length > 0) {
|
|
5454
|
+
await run(() => port.fields.updateItem(item, { browserFillEnabled: true }));
|
|
5455
|
+
done.push("browser fill");
|
|
5456
|
+
}
|
|
5457
|
+
return done;
|
|
5458
|
+
}
|
|
5459
|
+
function turnedOnSentence(done) {
|
|
5460
|
+
if (done.length === 0) return "Nothing here was off.";
|
|
5461
|
+
const list = done.length === 1 ? done[0] : `${done.slice(0, -1).join(", ")} and ${done[done.length - 1]}`;
|
|
5462
|
+
return `Turned on ${list}.`;
|
|
5463
|
+
}
|
|
5464
|
+
|
|
5371
5465
|
// src/ItemPane.tsx
|
|
5372
5466
|
var import_icons11 = require("@ai-matrx/design-system/icons");
|
|
5373
5467
|
var import_drafts = require("@ai-matrx/kit/drafts");
|
|
@@ -5949,6 +6043,9 @@ var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
|
5949
6043
|
var ENV_VALUE_KEY = "env_value";
|
|
5950
6044
|
var secureNoteDraft = () => ({ key: SECURE_NOTE_KEY, label: "Secure note", value: "", multiline: true, description: "Encrypted notes" });
|
|
5951
6045
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
6046
|
+
function confirmDelete(item) {
|
|
6047
|
+
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" });
|
|
6048
|
+
}
|
|
5952
6049
|
function ItemPane(props) {
|
|
5953
6050
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
5954
6051
|
const confirmed = useConfirmed();
|
|
@@ -5981,7 +6078,8 @@ function ItemPane(props) {
|
|
|
5981
6078
|
const [showBrowser, setShowBrowser] = (0, import_react28.useState)(false);
|
|
5982
6079
|
const [error, setError] = (0, import_react28.useState)(null);
|
|
5983
6080
|
const [destinations, setDestinations] = (0, import_react28.useState)({});
|
|
5984
|
-
const
|
|
6081
|
+
const [savedNew, setSavedNew] = (0, import_react28.useState)(false);
|
|
6082
|
+
const dirty = editing && !savedNew && isDirty(base, draft);
|
|
5985
6083
|
const declared = definition?.fields ?? [];
|
|
5986
6084
|
const prev = (0, import_react28.useRef)(null);
|
|
5987
6085
|
const paneRef = (0, import_react28.useRef)(null);
|
|
@@ -6004,8 +6102,11 @@ function ItemPane(props) {
|
|
|
6004
6102
|
setShowTags(false);
|
|
6005
6103
|
setShowDescription(false);
|
|
6006
6104
|
setShowRecovery(false);
|
|
6105
|
+
setSavedNew(false);
|
|
6007
6106
|
}, [item?.id, mode]);
|
|
6008
|
-
(0, import_react28.
|
|
6107
|
+
const onDirtyRef = (0, import_react28.useRef)(onDirty);
|
|
6108
|
+
onDirtyRef.current = onDirty;
|
|
6109
|
+
(0, import_react28.useEffect)(() => onDirtyRef.current(dirty), [dirty]);
|
|
6009
6110
|
const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
|
|
6010
6111
|
(0, import_react28.useEffect)(() => {
|
|
6011
6112
|
if (editing && dirty) (0, import_drafts.keepDraft)(keepKey, keptFieldsOf(draft), { basedOn: item?.updatedAt ?? "new" });
|
|
@@ -6062,6 +6163,8 @@ function ItemPane(props) {
|
|
|
6062
6163
|
const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
|
|
6063
6164
|
const [next, n] = await storeQueuedFiles(withCode, n0);
|
|
6064
6165
|
(0, import_drafts.dropKeptDraft)(keepKey);
|
|
6166
|
+
setSavedNew(true);
|
|
6167
|
+
onDirty(false);
|
|
6065
6168
|
onSaved(next, true, n, enrolled);
|
|
6066
6169
|
}
|
|
6067
6170
|
} catch (e) {
|
|
@@ -6095,8 +6198,7 @@ function ItemPane(props) {
|
|
|
6095
6198
|
}
|
|
6096
6199
|
async function remove() {
|
|
6097
6200
|
if (!item) return;
|
|
6098
|
-
|
|
6099
|
-
if (!ok) return;
|
|
6201
|
+
if (!await confirmDelete(item)) return;
|
|
6100
6202
|
setBusy(true);
|
|
6101
6203
|
try {
|
|
6102
6204
|
await port.remove(item);
|
|
@@ -6124,12 +6226,7 @@ function ItemPane(props) {
|
|
|
6124
6226
|
if (!item) return;
|
|
6125
6227
|
setError(null);
|
|
6126
6228
|
try {
|
|
6127
|
-
|
|
6128
|
-
for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
|
|
6129
|
-
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
6130
|
-
const codes = await port.authenticator.get(item);
|
|
6131
|
-
if (codes && !codes.enabled) await confirmed(() => port.authenticator.setEnabled(item, true));
|
|
6132
|
-
}
|
|
6229
|
+
await turnBackOn(port, item, fields, { run: confirmed });
|
|
6133
6230
|
onChanged();
|
|
6134
6231
|
} catch (e) {
|
|
6135
6232
|
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
|
|
@@ -6184,7 +6281,7 @@ function ItemPane(props) {
|
|
|
6184
6281
|
"Unsaved"
|
|
6185
6282
|
] }) : null,
|
|
6186
6283
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", disabled: busy, onClick: () => mode === "new" ? onCancelNew() : onMode("view"), children: dirty ? "Discard" : "Cancel" }),
|
|
6187
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { 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" })
|
|
6284
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { 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" })
|
|
6188
6285
|
] }) : item ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
6189
6286
|
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UseOnSiteButton, { port, item, pageUrl: host.page.url, onChanged: (next) => onChanged(next) }) : null,
|
|
6190
6287
|
host.fill && item.capabilities.canUse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
@@ -6352,7 +6449,8 @@ function ItemPane(props) {
|
|
|
6352
6449
|
else delete next[i];
|
|
6353
6450
|
return next;
|
|
6354
6451
|
});
|
|
6355
|
-
|
|
6452
|
+
const stored = r?.url || normalizeLoginUrl(u);
|
|
6453
|
+
if (stored && stored !== u) setDraft((d) => ({ ...d, loginUrls: d.loginUrls.map((x, j) => j === i && x === u ? stored : x) }));
|
|
6356
6454
|
}),
|
|
6357
6455
|
onRemove: () => patch({ loginUrls: draft.loginUrls.filter((_, j) => j !== i) }),
|
|
6358
6456
|
removeLabel: "Remove website"
|
|
@@ -6511,7 +6609,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6511
6609
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6512
6610
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6513
6611
|
}
|
|
6514
|
-
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 }) {
|
|
6612
|
+
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 }) {
|
|
6515
6613
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6516
6614
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6517
6615
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6532,7 +6630,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6532
6630
|
}
|
|
6533
6631
|
};
|
|
6534
6632
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6535
|
-
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);
|
|
6633
|
+
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);
|
|
6536
6634
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6537
6635
|
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: [
|
|
6538
6636
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6576,7 +6674,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6576
6674
|
] }) })
|
|
6577
6675
|
] });
|
|
6578
6676
|
}
|
|
6579
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6677
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, onAction, favorite }) {
|
|
6580
6678
|
const confirmed = useConfirmed();
|
|
6581
6679
|
const copy = useCopy();
|
|
6582
6680
|
const notify = useNotify();
|
|
@@ -6617,11 +6715,12 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6617
6715
|
...favoriteEntry ? [favoriteEntry] : [],
|
|
6618
6716
|
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6619
6717
|
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6718
|
+
...manageEntries(item, onAction),
|
|
6620
6719
|
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6621
6720
|
];
|
|
6622
6721
|
const entriesRef = (0, import_react29.useRef)(entries);
|
|
6623
6722
|
entriesRef.current = entries;
|
|
6624
|
-
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" });
|
|
6723
|
+
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" });
|
|
6625
6724
|
const menuItem = (e) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6626
6725
|
glyphOf(e),
|
|
6627
6726
|
e.label
|
|
@@ -6675,6 +6774,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6675
6774
|
copyEntries.map(menuItem),
|
|
6676
6775
|
copyEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6677
6776
|
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6777
|
+
entries.some((e) => e.kind === "manage") ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6778
|
+
entries.filter((e) => e.kind === "manage").map(menuItem),
|
|
6678
6779
|
hostEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6679
6780
|
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6680
6781
|
] })
|
|
@@ -6684,6 +6785,17 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6684
6785
|
}
|
|
6685
6786
|
);
|
|
6686
6787
|
}
|
|
6788
|
+
function manageEntries(item, onAction) {
|
|
6789
|
+
if (!onAction) return [];
|
|
6790
|
+
const canManage = item.capabilities.canManage;
|
|
6791
|
+
const offManage = !canManage && manageUnavailableReason(item) !== null;
|
|
6792
|
+
const run = (action) => () => onAction(item, action);
|
|
6793
|
+
return [
|
|
6794
|
+
{ id: "activity", kind: "manage", label: "Activity", onSelect: run("activity") },
|
|
6795
|
+
...canManage || offManage ? [{ id: "share", kind: "manage", label: "Share", onSelect: run("share"), disabled: !canManage }] : [],
|
|
6796
|
+
...canManage || offManage ? [{ id: "delete", kind: "manage", label: "Delete", onSelect: run("delete"), disabled: !canManage }] : []
|
|
6797
|
+
];
|
|
6798
|
+
}
|
|
6687
6799
|
|
|
6688
6800
|
// src/lists/TrashView.tsx
|
|
6689
6801
|
var import_react31 = require("react");
|
|
@@ -6764,8 +6876,16 @@ var import_react30 = require("react");
|
|
|
6764
6876
|
var import_controls24 = require("@ai-matrx/design-system/controls");
|
|
6765
6877
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
6766
6878
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6767
|
-
function RestorePanel({
|
|
6879
|
+
function RestorePanel({
|
|
6880
|
+
lists,
|
|
6881
|
+
item,
|
|
6882
|
+
restore,
|
|
6883
|
+
turnOn,
|
|
6884
|
+
onClose
|
|
6885
|
+
}) {
|
|
6768
6886
|
const [preview, setPreview] = (0, import_react30.useState)(null);
|
|
6887
|
+
const [restored, setRestored] = (0, import_react30.useState)(null);
|
|
6888
|
+
const [turnedOn, setTurnedOn] = (0, import_react30.useState)(null);
|
|
6769
6889
|
const [error, setError] = (0, import_react30.useState)(null);
|
|
6770
6890
|
const [busy, setBusy] = (0, import_react30.useState)(false);
|
|
6771
6891
|
const [loading, setLoading] = (0, import_react30.useState)(Boolean(lists.preview));
|
|
@@ -6794,13 +6914,54 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6794
6914
|
setError(null);
|
|
6795
6915
|
try {
|
|
6796
6916
|
const result = await restore(preview?.supported ? preview.deletionId : void 0);
|
|
6797
|
-
if (result)
|
|
6917
|
+
if (!result) return;
|
|
6918
|
+
if (turnOn && !result.alreadyRestored && preview?.supported && !preview.priorWasDisabled) setRestored(result);
|
|
6919
|
+
else onClose();
|
|
6798
6920
|
} catch (e) {
|
|
6799
6921
|
setError(e instanceof Error && e.message ? e.message : "Restore did not complete. Try again.");
|
|
6800
6922
|
} finally {
|
|
6801
6923
|
setBusy(false);
|
|
6802
6924
|
}
|
|
6803
6925
|
};
|
|
6926
|
+
const runTurnOn = async () => {
|
|
6927
|
+
if (!restored || !turnOn) return;
|
|
6928
|
+
setBusy(true);
|
|
6929
|
+
setError(null);
|
|
6930
|
+
try {
|
|
6931
|
+
const said = await turnOn(restored.item);
|
|
6932
|
+
if (said !== null) setTurnedOn(said);
|
|
6933
|
+
} catch (e) {
|
|
6934
|
+
setError(e instanceof Error && e.message ? e.message : "It could not be turned on. Turn it on from the item.");
|
|
6935
|
+
} finally {
|
|
6936
|
+
setBusy(false);
|
|
6937
|
+
}
|
|
6938
|
+
};
|
|
6939
|
+
if (restored) {
|
|
6940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
6941
|
+
Panel,
|
|
6942
|
+
{
|
|
6943
|
+
title: `Restored "${item.name}"`,
|
|
6944
|
+
size: "md",
|
|
6945
|
+
onClose,
|
|
6946
|
+
footer: turnedOn ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_controls24.Button, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
6947
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_controls24.Button, { variant: "quiet", onClick: onClose, children: "Leave off" }),
|
|
6948
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_controls24.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RestoreGlyph, {}), disabled: busy, onClick: () => void runTurnOn(), children: busy ? "Turning on\u2026" : "Turn these back on" })
|
|
6949
|
+
] }),
|
|
6950
|
+
children: [
|
|
6951
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(VaultSection, { title: turnedOn ? "Turned on" : "Back, turned off", children: [
|
|
6952
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Came back", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "text-foreground", children: [
|
|
6953
|
+
count(restored.restoredFields, "field"),
|
|
6954
|
+
", ",
|
|
6955
|
+
count(restored.restoredAttachments, "file")
|
|
6956
|
+
] }) }),
|
|
6957
|
+
turnedOn ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Now on", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { role: "status", className: "text-foreground", children: turnedOn }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Turns on", hint: "One press, nothing else changes", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-muted-foreground", children: "The item, its fields, codes and browser fill" }) }),
|
|
6958
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Stays off", hint: "Choose these again yourself", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-muted-foreground", children: "Sharing, sandbox use" }) })
|
|
6959
|
+
] }),
|
|
6960
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null
|
|
6961
|
+
]
|
|
6962
|
+
}
|
|
6963
|
+
);
|
|
6964
|
+
}
|
|
6804
6965
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
6805
6966
|
Panel,
|
|
6806
6967
|
{
|
|
@@ -6841,7 +7002,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6841
7002
|
setMessage(null);
|
|
6842
7003
|
try {
|
|
6843
7004
|
const r = await confirmed(() => port.lists.restore(item, deletionId));
|
|
6844
|
-
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files
|
|
7005
|
+
setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files, turned off.` });
|
|
6845
7006
|
onChanged();
|
|
6846
7007
|
return r;
|
|
6847
7008
|
} catch (e) {
|
|
@@ -6851,6 +7012,19 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6851
7012
|
setBusyId(null);
|
|
6852
7013
|
}
|
|
6853
7014
|
};
|
|
7015
|
+
const turnOn = async (item) => {
|
|
7016
|
+
try {
|
|
7017
|
+
const done = await turnBackOn(port, item, item.fields, { browserFill: true, run: confirmed });
|
|
7018
|
+
const said = turnedOnSentence(done);
|
|
7019
|
+
setMessage({ tone: "ok", text: `"${item.name}": ${said}` });
|
|
7020
|
+
onChanged();
|
|
7021
|
+
return said;
|
|
7022
|
+
} catch (e) {
|
|
7023
|
+
onChanged();
|
|
7024
|
+
if (wasCancelled(e)) return null;
|
|
7025
|
+
throw e;
|
|
7026
|
+
}
|
|
7027
|
+
};
|
|
6854
7028
|
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
|
|
6855
7029
|
header,
|
|
6856
7030
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(VaultSection, { title: "Trash", children: shown.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { children: deleted.length === 0 ? "The trash is empty." : "Nothing matches." }) : shown.map((item) => (
|
|
@@ -6864,7 +7038,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6864
7038
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_controls25.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6865
7039
|
] }, item.id)
|
|
6866
7040
|
)) }),
|
|
6867
|
-
restoring ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), onClose: () => setRestoring(null) }) : null,
|
|
7041
|
+
restoring ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), turnOn, onClose: () => setRestoring(null) }) : null,
|
|
6868
7042
|
message2 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { role: "status", className: message2.tone === "error" ? "px-1 text-sm text-destructive" : "px-1 text-sm text-muted-foreground", children: message2.text }) : null
|
|
6869
7043
|
] });
|
|
6870
7044
|
}
|
|
@@ -8158,22 +8332,10 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
8158
8332
|
] })
|
|
8159
8333
|
] }),
|
|
8160
8334
|
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,
|
|
8335
|
+
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,
|
|
8161
8336
|
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,
|
|
8162
8337
|
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,
|
|
8163
|
-
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
|
|
8164
|
-
onSignIn ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenu, { children: [
|
|
8165
|
-
/* @__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 }) }),
|
|
8166
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuContent, { align: "end", children: [
|
|
8167
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuItem, { onSelect: onSignIn, children: [
|
|
8168
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8169
|
-
"Sign me in"
|
|
8170
|
-
] }),
|
|
8171
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuItem, { onSelect: () => onOpen(itemId), children: [
|
|
8172
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ListGlyph, { className: "size-4" }),
|
|
8173
|
-
"Open item"
|
|
8174
|
-
] })
|
|
8175
|
-
] })
|
|
8176
|
-
] }) : null
|
|
8338
|
+
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
|
|
8177
8339
|
] });
|
|
8178
8340
|
}
|
|
8179
8341
|
|
|
@@ -8285,7 +8447,7 @@ function Group({ title, children }) {
|
|
|
8285
8447
|
children
|
|
8286
8448
|
] });
|
|
8287
8449
|
}
|
|
8288
|
-
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
8450
|
+
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
|
|
8289
8451
|
const [tagsOpen, setTagsOpen] = (0, import_react41.useState)(view.startsWith("tag:"));
|
|
8290
8452
|
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: [
|
|
8291
8453
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -8324,7 +8486,9 @@ function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, v
|
|
|
8324
8486
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ShieldGlyph, { className: "size-4 shrink-0" }),
|
|
8325
8487
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
|
|
8326
8488
|
/* @__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" })
|
|
8327
|
-
] }) : null
|
|
8489
|
+
] }) : null,
|
|
8490
|
+
onOpenWeb ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: ExternalGlyph, label: "Open on the web", onClick: onOpenWeb }) : null,
|
|
8491
|
+
onLock ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: LockGlyph, label: "Lock", onClick: onLock }) : null
|
|
8328
8492
|
] })
|
|
8329
8493
|
] });
|
|
8330
8494
|
}
|
|
@@ -8367,12 +8531,42 @@ function ImportWithLimits(props) {
|
|
|
8367
8531
|
if (state && "limits" in state) return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportPanel, { ...rest, limits: state.limits });
|
|
8368
8532
|
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" }) });
|
|
8369
8533
|
}
|
|
8370
|
-
function VaultApp(
|
|
8534
|
+
function VaultApp(given) {
|
|
8535
|
+
const props = { ...given, host: useOrganizationSettings(given.host ?? NO_HOST) };
|
|
8371
8536
|
const lock = props.host?.lock;
|
|
8372
8537
|
const locked = useLocked(lock);
|
|
8373
8538
|
const port = (0, import_react42.useMemo)(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
8374
8539
|
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 }) }) }) }) }) }) }) });
|
|
8375
8540
|
}
|
|
8541
|
+
function useOrganizationSettings(host) {
|
|
8542
|
+
const knobs = host.knobs;
|
|
8543
|
+
const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0);
|
|
8544
|
+
const [read, setRead] = (0, import_react42.useState)(null);
|
|
8545
|
+
(0, import_react42.useEffect)(() => {
|
|
8546
|
+
if (!needs || !knobs) return;
|
|
8547
|
+
let live = true;
|
|
8548
|
+
knobs().then(
|
|
8549
|
+
(r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB) }),
|
|
8550
|
+
() => void 0
|
|
8551
|
+
);
|
|
8552
|
+
return () => {
|
|
8553
|
+
live = false;
|
|
8554
|
+
};
|
|
8555
|
+
}, [needs, knobs]);
|
|
8556
|
+
if (!read) return host;
|
|
8557
|
+
return {
|
|
8558
|
+
...host,
|
|
8559
|
+
...host.revealSeconds === void 0 && read.reveal !== null ? { revealSeconds: read.reveal } : {},
|
|
8560
|
+
...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {}
|
|
8561
|
+
};
|
|
8562
|
+
}
|
|
8563
|
+
var NO_STORE = () => () => void 0;
|
|
8564
|
+
var NOTHING = () => null;
|
|
8565
|
+
function useHostPrompts(capture, fillSetup) {
|
|
8566
|
+
const prompt = (0, import_react42.useSyncExternalStore)(capture ? capture.subscribe : NO_STORE, capture ? capture.get : NOTHING, capture ? capture.get : NOTHING);
|
|
8567
|
+
const setup = (0, import_react42.useSyncExternalStore)(fillSetup ? fillSetup.subscribe : NO_STORE, fillSetup ? fillSetup.get : NOTHING, fillSetup ? fillSetup.get : NOTHING);
|
|
8568
|
+
return prompt !== null || setup?.status === "off";
|
|
8569
|
+
}
|
|
8376
8570
|
function LockedScreen({ lock }) {
|
|
8377
8571
|
const [busy, setBusy] = (0, import_react42.useState)(false);
|
|
8378
8572
|
const [error, setError] = (0, import_react42.useState)(null);
|
|
@@ -8460,6 +8654,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8460
8654
|
document.addEventListener("keydown", onKey);
|
|
8461
8655
|
return () => document.removeEventListener("keydown", onKey);
|
|
8462
8656
|
}, []);
|
|
8657
|
+
const keepSearchFocus = (0, import_react42.useRef)(false);
|
|
8658
|
+
(0, import_react42.useEffect)(() => {
|
|
8659
|
+
if (!keepSearchFocus.current) return;
|
|
8660
|
+
keepSearchFocus.current = false;
|
|
8661
|
+
const search = rootRef.current?.querySelector('input[aria-label^="Search"]');
|
|
8662
|
+
if (!search || document.activeElement === search) return;
|
|
8663
|
+
search.focus();
|
|
8664
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
8665
|
+
}, [loc.q]);
|
|
8666
|
+
const hasPrompts = useHostPrompts(host.capture, host.fillSetup);
|
|
8463
8667
|
const knobsRef = (0, import_react42.useRef)(host.knobs);
|
|
8464
8668
|
knobsRef.current = host.knobs;
|
|
8465
8669
|
const [signedOut, setSignedOut] = (0, import_react42.useState)(false);
|
|
@@ -8602,6 +8806,25 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8602
8806
|
notify(e instanceof Error ? e.message : "Favorites could not be saved.", "error");
|
|
8603
8807
|
});
|
|
8604
8808
|
};
|
|
8809
|
+
const deletedItem = (id) => {
|
|
8810
|
+
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8811
|
+
dirty.current = false;
|
|
8812
|
+
if (loc.itemId === id) move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8813
|
+
notify("Moved to Trash");
|
|
8814
|
+
load();
|
|
8815
|
+
};
|
|
8816
|
+
const rowAction = (item, action) => {
|
|
8817
|
+
if (action !== "delete") return go({ view: loc.view === "page" ? "all" : loc.view, itemId: item.id, mode: "view", panel: action });
|
|
8818
|
+
void confirmDelete(item).then(async (ok) => {
|
|
8819
|
+
if (!ok) return;
|
|
8820
|
+
try {
|
|
8821
|
+
await port.remove(item);
|
|
8822
|
+
deletedItem(item.id);
|
|
8823
|
+
} catch (e) {
|
|
8824
|
+
notify(e instanceof Error && e.message ? e.message : "Deleting failed.", "error");
|
|
8825
|
+
}
|
|
8826
|
+
});
|
|
8827
|
+
};
|
|
8605
8828
|
if (error) {
|
|
8606
8829
|
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: [
|
|
8607
8830
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
@@ -8685,6 +8908,27 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8685
8908
|
compactActions
|
|
8686
8909
|
] })
|
|
8687
8910
|
] });
|
|
8911
|
+
const newItem = () => go({ itemId: null, mode: "new", kind: null, panel: null });
|
|
8912
|
+
const pageHeader = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col gap-2", "data-vault-page-header": "", children: [
|
|
8913
|
+
compactHeader,
|
|
8914
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
8915
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8916
|
+
import_controls35.SearchField,
|
|
8917
|
+
{
|
|
8918
|
+
value: loc.q,
|
|
8919
|
+
onChange: (e) => {
|
|
8920
|
+
keepSearchFocus.current = true;
|
|
8921
|
+
go({ q: e.target.value }, "replace");
|
|
8922
|
+
},
|
|
8923
|
+
placeholder: "Search the vault",
|
|
8924
|
+
"aria-label": "Search the vault",
|
|
8925
|
+
className: "min-w-0 flex-1"
|
|
8926
|
+
}
|
|
8927
|
+
),
|
|
8928
|
+
compactActions,
|
|
8929
|
+
/* @__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 })
|
|
8930
|
+
] })
|
|
8931
|
+
] });
|
|
8688
8932
|
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 };
|
|
8689
8933
|
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8690
8934
|
PageView,
|
|
@@ -8692,8 +8936,6 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8692
8936
|
port,
|
|
8693
8937
|
page: host.page,
|
|
8694
8938
|
fill: host.fill,
|
|
8695
|
-
capture: host.capture,
|
|
8696
|
-
fillSetup: host.fillSetup,
|
|
8697
8939
|
newPasswordFields: host.newPasswordFields,
|
|
8698
8940
|
items: inThisVault,
|
|
8699
8941
|
definitions,
|
|
@@ -8701,10 +8943,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8701
8943
|
onNewForPage: (url) => go({ mode: "new", kind: null, url, itemId: null, panel: null }),
|
|
8702
8944
|
onBrowse: () => go({ view: "all", itemId: null }),
|
|
8703
8945
|
onChanged: load,
|
|
8704
|
-
|
|
8705
|
-
compactHeader,
|
|
8706
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex justify-end", children: compactActions })
|
|
8707
|
-
] }) } : {}
|
|
8946
|
+
header: pageHeader
|
|
8708
8947
|
}
|
|
8709
8948
|
) : null;
|
|
8710
8949
|
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);
|
|
@@ -8719,11 +8958,15 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8719
8958
|
selectedId: loc.itemId,
|
|
8720
8959
|
onSelect: (id) => go({ itemId: id, mode: "view", kind: null, panel: null }),
|
|
8721
8960
|
query: loc.q,
|
|
8722
|
-
onQuery: (q) =>
|
|
8961
|
+
onQuery: (q) => {
|
|
8962
|
+
if (loc.view === "page" && host.page && !q) keepSearchFocus.current = true;
|
|
8963
|
+
go({ q }, "replace");
|
|
8964
|
+
},
|
|
8723
8965
|
sort: loc.sort,
|
|
8724
8966
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8725
8967
|
canSortViewed: port.lists.recents !== void 0,
|
|
8726
|
-
onNew:
|
|
8968
|
+
onNew: newItem,
|
|
8969
|
+
onItemAction: rowAction,
|
|
8727
8970
|
onRefresh: refresh,
|
|
8728
8971
|
refreshing,
|
|
8729
8972
|
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
@@ -8798,13 +9041,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8798
9041
|
setNotice(n);
|
|
8799
9042
|
notify("Saved");
|
|
8800
9043
|
},
|
|
8801
|
-
onDeleted:
|
|
8802
|
-
setItems((cur) => cur.filter((i) => i.id !== id));
|
|
8803
|
-
dirty.current = false;
|
|
8804
|
-
move({ ...loc, itemId: null, mode: "view", panel: null }, "push");
|
|
8805
|
-
notify("Moved to Trash");
|
|
8806
|
-
load();
|
|
8807
|
-
},
|
|
9044
|
+
onDeleted: deletedItem,
|
|
8808
9045
|
onDirty: (d) => {
|
|
8809
9046
|
dirty.current = d;
|
|
8810
9047
|
},
|
|
@@ -8865,6 +9102,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8865
9102
|
/* @__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." }),
|
|
8866
9103
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: refresh, children: "Try again" })
|
|
8867
9104
|
] }) : null,
|
|
9105
|
+
hasPrompts ? (
|
|
9106
|
+
// "Save this login?" and "Turn on filling" show above the list in every view, not only "This page".
|
|
9107
|
+
/* @__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: [
|
|
9108
|
+
host.fillSetup ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(FillSetupCard, { fillSetup: host.fillSetup }) : null,
|
|
9109
|
+
host.capture ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CaptureCard, { capture: host.capture, onChanged: load }) : null
|
|
9110
|
+
] })
|
|
9111
|
+
) : null,
|
|
8868
9112
|
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: [
|
|
8869
9113
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8870
9114
|
"Couldn\u2019t load ",
|
|
@@ -8890,7 +9134,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8890
9134
|
onPanel: (p) => go({ panel: p }),
|
|
8891
9135
|
nativeProvider: host.nativeProvider,
|
|
8892
9136
|
hasNativeImport: host.nativeImport !== void 0,
|
|
8893
|
-
hasPage: host.page !== void 0
|
|
9137
|
+
hasPage: host.page !== void 0,
|
|
9138
|
+
onLock: host.lock?.lock ? () => void host.lock?.lock?.() : void 0,
|
|
9139
|
+
onOpenWeb: host.openWebVault
|
|
8894
9140
|
}
|
|
8895
9141
|
) : null,
|
|
8896
9142
|
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,
|
|
@@ -9129,7 +9375,7 @@ function createFieldsPort(ctx) {
|
|
|
9129
9375
|
const body = { initiation: "user" };
|
|
9130
9376
|
if (patch.uriMatchMode !== void 0) body.uri_match_mode = patch.uriMatchMode;
|
|
9131
9377
|
if (patch.browserFillEnabled !== void 0) body.browser_fill_enabled = patch.browserFillEnabled;
|
|
9132
|
-
if (patch.loginUrls !== void 0) body.login_urls = patch.loginUrls;
|
|
9378
|
+
if (patch.loginUrls !== void 0) body.login_urls = normalizeLoginUrls(patch.loginUrls);
|
|
9133
9379
|
if (patch.active !== void 0) body.status = patch.active ? "active" : "disabled";
|
|
9134
9380
|
await account3.updateItem(api, { path: { item_id: item.id }, body }, ctx.optsFor(item));
|
|
9135
9381
|
return reread(item);
|
|
@@ -9141,6 +9387,33 @@ function createFieldsPort(ctx) {
|
|
|
9141
9387
|
};
|
|
9142
9388
|
}
|
|
9143
9389
|
|
|
9390
|
+
// src/server-reasons.ts
|
|
9391
|
+
var GENERIC = [/please check your input/i, /^\s*request failed\s*\(\d+\)\s*$/i, /^\s*bad request\.?\s*$/i, /^\s*HTTP \d+\s*$/i];
|
|
9392
|
+
var isGeneric = (s) => GENERIC.some((re) => re.test(s));
|
|
9393
|
+
function cleanReason(detail) {
|
|
9394
|
+
const s = detail.replace(/^\s*validation error:\s*/i, "").replace(/^\s*value error,\s*/i, "").trim();
|
|
9395
|
+
return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
|
|
9396
|
+
}
|
|
9397
|
+
function serverReason(e) {
|
|
9398
|
+
if (!e || typeof e !== "object") return null;
|
|
9399
|
+
const { status, detail, message: message2 } = e;
|
|
9400
|
+
if (typeof status !== "number" || status < 400 || status >= 500) return null;
|
|
9401
|
+
if (typeof detail !== "string" || !detail.trim() || isGeneric(detail)) return null;
|
|
9402
|
+
const shown = typeof message2 === "string" ? message2 : "";
|
|
9403
|
+
if (shown && !isGeneric(shown)) return null;
|
|
9404
|
+
return cleanReason(detail);
|
|
9405
|
+
}
|
|
9406
|
+
function withReason(e) {
|
|
9407
|
+
const reason = serverReason(e);
|
|
9408
|
+
if (reason) Object.assign(e, { message: reason, userMessage: reason });
|
|
9409
|
+
return e;
|
|
9410
|
+
}
|
|
9411
|
+
function withServerReasons(api) {
|
|
9412
|
+
const wrapped = Object.create(api);
|
|
9413
|
+
wrapped.call = (...args) => api.call(...args).catch((e) => Promise.reject(withReason(e)));
|
|
9414
|
+
return wrapped;
|
|
9415
|
+
}
|
|
9416
|
+
|
|
9144
9417
|
// src/io/api.ts
|
|
9145
9418
|
var account4 = __toESM(require("@ai-matrx/api/account"), 1);
|
|
9146
9419
|
var orgOpts = (organizationId) => organizationId ? { organizationId } : void 0;
|
|
@@ -9413,7 +9686,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
9413
9686
|
definition_key: definition.key,
|
|
9414
9687
|
provider_key: definition.providerKey,
|
|
9415
9688
|
tags: draft.tags,
|
|
9416
|
-
login_urls: draft.loginUrls,
|
|
9689
|
+
login_urls: normalizeLoginUrls(draft.loginUrls),
|
|
9417
9690
|
notes: draft.notes || null,
|
|
9418
9691
|
generate_field_key: generateFieldKey,
|
|
9419
9692
|
initiation: "user",
|
|
@@ -9610,7 +9883,8 @@ async function retrying(run, tries = 3) {
|
|
|
9610
9883
|
}
|
|
9611
9884
|
}
|
|
9612
9885
|
}
|
|
9613
|
-
function createApiVaultPort(
|
|
9886
|
+
function createApiVaultPort(hostApi, options = {}) {
|
|
9887
|
+
const api = withServerReasons(hostApi);
|
|
9614
9888
|
let defs = /* @__PURE__ */ new Map();
|
|
9615
9889
|
let auth = /* @__PURE__ */ new Map();
|
|
9616
9890
|
let orgs = [];
|
|
@@ -9765,6 +10039,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9765
10039
|
const declared = definition.fields;
|
|
9766
10040
|
const encrypted = declared.filter((f) => f.storage === "encrypted" && (draft.values[f.key] ?? "") !== "");
|
|
9767
10041
|
const meta = declared.filter((f) => f.storage === "metadata" && (draft.values[f.key] ?? "") !== "");
|
|
10042
|
+
const loginUrls = normalizeLoginUrls(draft.loginUrls);
|
|
9768
10043
|
const w = await account9.createItem(api, {
|
|
9769
10044
|
body: {
|
|
9770
10045
|
display_name: draft.name.trim(),
|
|
@@ -9772,10 +10047,10 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9772
10047
|
definition_key: definition.key,
|
|
9773
10048
|
provider_key: definition.providerKey,
|
|
9774
10049
|
tags: draft.tags,
|
|
9775
|
-
login_urls:
|
|
10050
|
+
login_urls: loginUrls,
|
|
9776
10051
|
// A login a person saves with its website is offered on that website (the server's own
|
|
9777
10052
|
// default is off, which made "Save a login" on a page answer "No saved login" there).
|
|
9778
|
-
...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } :
|
|
10053
|
+
...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } : loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
|
|
9779
10054
|
notes: draft.notes || null,
|
|
9780
10055
|
principal: organizationId ? { type: "organization", organization_id: organizationId } : { type: "user" },
|
|
9781
10056
|
initiation: "user",
|
|
@@ -9802,7 +10077,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9802
10077
|
else body.description = draft.description.trim();
|
|
9803
10078
|
}
|
|
9804
10079
|
if (JSON.stringify(draft.tags) !== JSON.stringify(item.tags)) body.tags = draft.tags;
|
|
9805
|
-
if (JSON.stringify(draft.loginUrls) !== JSON.stringify(item.loginUrls)) body.login_urls = draft.loginUrls;
|
|
10080
|
+
if (JSON.stringify(draft.loginUrls) !== JSON.stringify(item.loginUrls)) body.login_urls = normalizeLoginUrls(draft.loginUrls);
|
|
9806
10081
|
if (draft.notes !== item.notes) {
|
|
9807
10082
|
if (draft.notes === "") body.clear_notes = true;
|
|
9808
10083
|
else body.notes = draft.notes;
|
|
@@ -9834,20 +10109,6 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9834
10109
|
};
|
|
9835
10110
|
}
|
|
9836
10111
|
|
|
9837
|
-
// src/knobs.ts
|
|
9838
|
-
var import_knobs = require("@ai-matrx/data/knobs");
|
|
9839
|
-
var FRESH_MS = 6e4;
|
|
9840
|
-
function createVaultKnobs(client, address) {
|
|
9841
|
-
const reader = (0, import_knobs.createKnobReader)(client);
|
|
9842
|
-
let kept = null;
|
|
9843
|
-
return async () => {
|
|
9844
|
-
if (kept && Date.now() - kept.at < FRESH_MS) return kept.resolved;
|
|
9845
|
-
const snap = await reader.snapshot(address);
|
|
9846
|
-
kept = { at: Date.now(), resolved: snap.resolved };
|
|
9847
|
-
return snap.resolved;
|
|
9848
|
-
};
|
|
9849
|
-
}
|
|
9850
|
-
|
|
9851
10112
|
// src/agent-context.ts
|
|
9852
10113
|
var hostOf = (url) => {
|
|
9853
10114
|
try {
|