@ai-matrx/vault 0.1.18 → 0.1.20
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 +29 -0
- package/dist/index.cjs +377 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -5
- package/dist/index.d.ts +49 -5
- package/dist/index.js +398 -173
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -671,7 +671,7 @@ var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
|
|
|
671
671
|
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
672
672
|
var MASK = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
673
673
|
function SecretText({ value, multiline }) {
|
|
674
|
-
if (multiline || value.length > 200) return /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap break-all font-mono text-sm", children: value });
|
|
674
|
+
if (multiline || value.length > 200 || value.includes("\n")) return /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap break-all font-mono text-sm", children: value });
|
|
675
675
|
return /* @__PURE__ */ jsx5("span", { className: "break-all font-mono text-sm tracking-wide", children: [...value].map((ch, i) => /* @__PURE__ */ jsx5("span", { className: /[0-9]/.test(ch) ? "text-primary" : /[^A-Za-z0-9]/.test(ch) ? "text-warning" : void 0, children: ch }, i)) });
|
|
676
676
|
}
|
|
677
677
|
var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
|
|
@@ -807,18 +807,19 @@ function EditRow({ label, hint: hint2, value, onChange, placeholder, secret = fa
|
|
|
807
807
|
}
|
|
808
808
|
);
|
|
809
809
|
}
|
|
810
|
-
function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue }) {
|
|
810
|
+
function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue, multiline = false }) {
|
|
811
811
|
const [shown, setShown] = useState5(false);
|
|
812
812
|
return /* @__PURE__ */ jsx5(
|
|
813
813
|
VaultRow,
|
|
814
814
|
{
|
|
815
815
|
label: /* @__PURE__ */ jsx5(Field2, { className: "w-full", value: label, onChange: (e) => onLabel(e.target.value), placeholder: "Name", "aria-label": "Field name" }),
|
|
816
|
+
top: multiline,
|
|
816
817
|
actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
817
|
-
secret && value ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
|
|
818
|
+
secret && value && !multiline ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
|
|
818
819
|
extra,
|
|
819
820
|
/* @__PURE__ */ jsx5(Button2, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx5(XGlyph, {}), "aria-label": "Remove field", onClick: onRemove })
|
|
820
821
|
] }),
|
|
821
|
-
children: /* @__PURE__ */ jsx5(
|
|
822
|
+
children: multiline ? /* @__PURE__ */ jsx5(Textarea, { className: "w-full", value, onChange: (e) => onValue(e.target.value), rows: 4, placeholder: secret ? "Encrypted, hidden until shown" : "Value", autoComplete: "off", spellCheck: !secret, "aria-label": label ? `${label} value` : "Field value" }) : /* @__PURE__ */ jsx5(
|
|
822
823
|
Field2,
|
|
823
824
|
{
|
|
824
825
|
className: "w-full",
|
|
@@ -860,6 +861,7 @@ function locationFromParams(params, itemId = params.get("item")) {
|
|
|
860
861
|
mode: mode === "edit" || mode === "new" ? mode : "view",
|
|
861
862
|
kind: params.get("kind"),
|
|
862
863
|
url: params.get("url") ?? "",
|
|
864
|
+
...params.get("name") ? { name: params.get("name") ?? "" } : {},
|
|
863
865
|
panel: params.get("panel")
|
|
864
866
|
};
|
|
865
867
|
}
|
|
@@ -872,6 +874,7 @@ function locationToParams(loc) {
|
|
|
872
874
|
if (loc.mode !== "view") q.set("mode", loc.mode);
|
|
873
875
|
if (loc.kind) q.set("kind", loc.kind);
|
|
874
876
|
if (loc.url) q.set("url", loc.url);
|
|
877
|
+
if (loc.name) q.set("name", loc.name);
|
|
875
878
|
if (loc.panel) q.set("panel", loc.panel);
|
|
876
879
|
return q;
|
|
877
880
|
}
|
|
@@ -935,6 +938,7 @@ function sortItems(items, sort, recents) {
|
|
|
935
938
|
if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
936
939
|
return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
937
940
|
}
|
|
941
|
+
var SECURE_NOTE_KEY = "secure_notes";
|
|
938
942
|
function draftOf(item) {
|
|
939
943
|
return {
|
|
940
944
|
name: item?.name ?? "",
|
|
@@ -985,7 +989,9 @@ function rebaseDraft(oldBase, newBase, draft) {
|
|
|
985
989
|
secrets: draft.secrets,
|
|
986
990
|
custom,
|
|
987
991
|
removed: draft.removed,
|
|
988
|
-
authenticator: draft.authenticator
|
|
992
|
+
authenticator: draft.authenticator,
|
|
993
|
+
...draft.browser ? { browser: draft.browser } : {},
|
|
994
|
+
...draft.fieldSettings ? { fieldSettings: draft.fieldSettings } : {}
|
|
989
995
|
};
|
|
990
996
|
}
|
|
991
997
|
function panesShown(mode, specialView, showingDetail) {
|
|
@@ -1013,7 +1019,8 @@ var FAMILY_LABELS = {
|
|
|
1013
1019
|
signing_files: "Signing & files"
|
|
1014
1020
|
};
|
|
1015
1021
|
var COMMON_DEFINITION_KEYS = ["website_login", "username_password", "api_key", "env_value", "database_login", "custom"];
|
|
1016
|
-
var MULTILINE = /(json|pem|private_key|certificate|cert|bundle|document|recovery_codes)/;
|
|
1022
|
+
var MULTILINE = /(json|pem|private_key|certificate|cert|bundle|document|recovery_codes|(^|_)notes?($|_))/;
|
|
1023
|
+
var isMultilineKey = (key) => MULTILINE.test(key);
|
|
1017
1024
|
var SECRET = /(password|secret|token|api_key|private|passphrase|credential|seed|key$|_key)/;
|
|
1018
1025
|
var URLISH = /(url|uri|endpoint|webhook|hook)/;
|
|
1019
1026
|
function humanize(key) {
|
|
@@ -1912,10 +1919,16 @@ function QrScanPanel({ open, onResult, onClose }) {
|
|
|
1912
1919
|
/* @__PURE__ */ jsx10("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
|
|
1913
1920
|
] });
|
|
1914
1921
|
}
|
|
1915
|
-
function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status }) {
|
|
1922
|
+
function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status, autoStartCamera = false }) {
|
|
1916
1923
|
const file = useRef8(null);
|
|
1917
1924
|
const canScan = useCanScan();
|
|
1918
1925
|
const [scanning, setScanning] = useState10(false);
|
|
1926
|
+
const autoStarted = useRef8(false);
|
|
1927
|
+
useEffect10(() => {
|
|
1928
|
+
if (!autoStartCamera || !canScan || disabled || autoStarted.current || value) return;
|
|
1929
|
+
autoStarted.current = true;
|
|
1930
|
+
setScanning(true);
|
|
1931
|
+
}, [autoStartCamera, canScan, disabled, value]);
|
|
1919
1932
|
const [reading, setReading] = useState10(false);
|
|
1920
1933
|
const [imageError, setImageError] = useState10(null);
|
|
1921
1934
|
const [dragging, setDragging] = useState10(false);
|
|
@@ -2221,7 +2234,7 @@ function normalizeWebsite(raw) {
|
|
|
2221
2234
|
return null;
|
|
2222
2235
|
}
|
|
2223
2236
|
}
|
|
2224
|
-
function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onDone }) {
|
|
2237
|
+
function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onAdded, onDone }) {
|
|
2225
2238
|
const confirmed = useConfirmed();
|
|
2226
2239
|
const candidates = items.filter((i) => !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
|
|
2227
2240
|
const [input, setInput] = useState12("");
|
|
@@ -2274,6 +2287,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2274
2287
|
setInput("");
|
|
2275
2288
|
setImage(null);
|
|
2276
2289
|
setSaved(next);
|
|
2290
|
+
onAdded?.(next);
|
|
2277
2291
|
onChanged();
|
|
2278
2292
|
} catch (e) {
|
|
2279
2293
|
setError(wasCancelled(e) ? "Not confirmed, so nothing was added." : otpActionError(e, "add it"));
|
|
@@ -2300,6 +2314,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2300
2314
|
label: "Setup key",
|
|
2301
2315
|
value: input,
|
|
2302
2316
|
autoFocus: true,
|
|
2317
|
+
autoStartCamera: true,
|
|
2303
2318
|
disabled: busy,
|
|
2304
2319
|
onChange: (v) => {
|
|
2305
2320
|
setImage(null);
|
|
@@ -2381,7 +2396,23 @@ function otpGroups(items, entries, query, hidden = /* @__PURE__ */ new Set()) {
|
|
|
2381
2396
|
const rank = (k) => k === "me" ? 0 : k === "shared" ? 2 : 1;
|
|
2382
2397
|
return [...groups.entries()].sort(([a, x], [b, y]) => rank(a) - rank(b) || x.label.localeCompare(y.label)).map(([key, g]) => ({ key, ...g }));
|
|
2383
2398
|
}
|
|
2384
|
-
function
|
|
2399
|
+
function withAdded(items, added) {
|
|
2400
|
+
if (added.size === 0) return items;
|
|
2401
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2402
|
+
const out = items.map((i) => {
|
|
2403
|
+
seen.add(i.id);
|
|
2404
|
+
const mine = added.get(i.id);
|
|
2405
|
+
return mine && !i.authenticator ? { ...i, authenticator: mine.authenticator, name: mine.name } : i;
|
|
2406
|
+
});
|
|
2407
|
+
for (const [id, a] of added) if (!seen.has(id)) out.push(a);
|
|
2408
|
+
return out;
|
|
2409
|
+
}
|
|
2410
|
+
function AuthenticatorView({ port, host, items: listed, definitions, query, onOpen, onChanged, header }) {
|
|
2411
|
+
const [added, setAdded] = useState13(/* @__PURE__ */ new Map());
|
|
2412
|
+
const items = withAdded(listed, added);
|
|
2413
|
+
useEffect11(() => {
|
|
2414
|
+
if (added.size > 0 && [...added.keys()].every((id) => listed.some((i) => i.id === id && i.authenticator))) setAdded(/* @__PURE__ */ new Map());
|
|
2415
|
+
}, [listed, added]);
|
|
2385
2416
|
const [entries, setEntries] = useState13(/* @__PURE__ */ new Map());
|
|
2386
2417
|
const [hidden, setHidden] = useState13(/* @__PURE__ */ new Set());
|
|
2387
2418
|
const [adding, setAdding] = useState13(false);
|
|
@@ -2397,7 +2428,7 @@ function AuthenticatorView({ port, host, items, definitions, query, onOpen, onCh
|
|
|
2397
2428
|
return () => {
|
|
2398
2429
|
live = false;
|
|
2399
2430
|
};
|
|
2400
|
-
}, [port,
|
|
2431
|
+
}, [port, listed, added]);
|
|
2401
2432
|
const groups = otpGroups(items, entries, query, hidden);
|
|
2402
2433
|
const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
|
|
2403
2434
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
@@ -2443,6 +2474,7 @@ function AuthenticatorView({ port, host, items, definitions, query, onOpen, onCh
|
|
|
2443
2474
|
definitions,
|
|
2444
2475
|
onClose: () => setAdding(false),
|
|
2445
2476
|
onChanged,
|
|
2477
|
+
onAdded: (item) => setAdded((cur) => new Map(cur).set(item.id, item)),
|
|
2446
2478
|
onDone: (id) => {
|
|
2447
2479
|
setAdding(false);
|
|
2448
2480
|
onOpen(id);
|
|
@@ -3852,7 +3884,7 @@ var MAX_FAILURES_IN_A_ROW = 5;
|
|
|
3852
3884
|
var failureText = (cause) => cause instanceof Error && cause.message ? cause.message : "The server refused this one.";
|
|
3853
3885
|
async function runImport(input) {
|
|
3854
3886
|
const { io, organizationId, lines, keys, confirmed } = input;
|
|
3855
|
-
const result = { created: [], failed: [], withOtp: 0, stoppedEarly: false, untried: [] };
|
|
3887
|
+
const result = { created: [], failed: [], withOtp: 0, needOtp: [], stoppedEarly: false, untried: [] };
|
|
3856
3888
|
let streak = 0;
|
|
3857
3889
|
for (let i = 0; i < lines.length; i += 1) {
|
|
3858
3890
|
const line = lines[i];
|
|
@@ -3871,7 +3903,10 @@ async function runImport(input) {
|
|
|
3871
3903
|
try {
|
|
3872
3904
|
const made = await confirmed(() => io.createImported(command.body, organizationId, key));
|
|
3873
3905
|
result.created.push(made);
|
|
3874
|
-
if (command.hasOtp)
|
|
3906
|
+
if (command.hasOtp) {
|
|
3907
|
+
result.withOtp += 1;
|
|
3908
|
+
result.needOtp.push(made);
|
|
3909
|
+
}
|
|
3875
3910
|
streak = 0;
|
|
3876
3911
|
} catch (cause) {
|
|
3877
3912
|
const reason = failureText(cause);
|
|
@@ -4471,8 +4506,9 @@ var STATE_BADGE = {
|
|
|
4471
4506
|
unsupported: { text: "Not supported", tone: "neutral" }
|
|
4472
4507
|
};
|
|
4473
4508
|
var ME = "me";
|
|
4474
|
-
function ImportPanel({ port, host, items, organizations, onClose, onChanged, limits }) {
|
|
4509
|
+
function ImportPanel({ port, host, items, definitions, organizations, onClose, onChanged, limits }) {
|
|
4475
4510
|
const confirmed = useConfirmed();
|
|
4511
|
+
const [otpFor, setOtpFor] = useState19(null);
|
|
4476
4512
|
const fileInput = useRef12(null);
|
|
4477
4513
|
const abort = useRef12(null);
|
|
4478
4514
|
const stop = useRef12(false);
|
|
@@ -4580,6 +4616,7 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4580
4616
|
failed: result.failed,
|
|
4581
4617
|
skipped,
|
|
4582
4618
|
withOtp: (previous?.withOtp ?? 0) + result.withOtp,
|
|
4619
|
+
needOtp: [...previous?.needOtp ?? [], ...result.needOtp],
|
|
4583
4620
|
untried: result.untried
|
|
4584
4621
|
};
|
|
4585
4622
|
setDone(merged);
|
|
@@ -4605,7 +4642,7 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4605
4642
|
setRunning({ done: 0, total: chosen });
|
|
4606
4643
|
try {
|
|
4607
4644
|
const made = await confirmed(() => port.io.importEnv(text, organizationId, injectSandbox));
|
|
4608
|
-
setDone({ created: made, failed: [], skipped: draft.entries.length - chosen, withOtp: 0, untried: [] });
|
|
4645
|
+
setDone({ created: made, failed: [], skipped: draft.entries.length - chosen, withOtp: 0, needOtp: [], untried: [] });
|
|
4609
4646
|
if (made.length > 0) onChanged();
|
|
4610
4647
|
} catch (cause) {
|
|
4611
4648
|
setError(cause instanceof Error ? cause.message : "The import could not finish.");
|
|
@@ -4720,9 +4757,32 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4720
4757
|
plural(done.withOtp, "login"),
|
|
4721
4758
|
" still need the one-time password added."
|
|
4722
4759
|
] }) }) : null,
|
|
4760
|
+
done.needOtp.map((made) => {
|
|
4761
|
+
const now = items.find((i) => i.id === made.id);
|
|
4762
|
+
if (now?.authenticator) return null;
|
|
4763
|
+
return /* @__PURE__ */ jsx19(VaultRow, { label: "Authenticator", children: /* @__PURE__ */ jsxs18("button", { type: "button", className: "truncate text-left text-primary hover:underline", onClick: () => setOtpFor(made.id), children: [
|
|
4764
|
+
"Set up authenticator for ",
|
|
4765
|
+
made.name
|
|
4766
|
+
] }) }, `otp:${made.id}`);
|
|
4767
|
+
}),
|
|
4723
4768
|
done.failed.map((f) => /* @__PURE__ */ jsx19(VaultRow, { label: f.title, children: /* @__PURE__ */ jsx19("span", { className: "block truncate text-destructive", title: f.reason, children: f.reason }) }, f.key))
|
|
4724
4769
|
] }) : null,
|
|
4725
|
-
/* @__PURE__ */ jsx19(ErrorLine, { message: error })
|
|
4770
|
+
/* @__PURE__ */ jsx19(ErrorLine, { message: error }),
|
|
4771
|
+
otpFor ? /* @__PURE__ */ jsx19(
|
|
4772
|
+
AddOtpPanel,
|
|
4773
|
+
{
|
|
4774
|
+
port,
|
|
4775
|
+
items,
|
|
4776
|
+
definitions,
|
|
4777
|
+
itemId: otpFor,
|
|
4778
|
+
onClose: () => setOtpFor(null),
|
|
4779
|
+
onChanged,
|
|
4780
|
+
onDone: () => {
|
|
4781
|
+
setOtpFor(null);
|
|
4782
|
+
onChanged();
|
|
4783
|
+
}
|
|
4784
|
+
}
|
|
4785
|
+
) : null
|
|
4726
4786
|
] });
|
|
4727
4787
|
}
|
|
4728
4788
|
function toggle(set, key, on) {
|
|
@@ -4760,7 +4820,7 @@ import { Button as Button23, SearchField } from "@ai-matrx/design-system/control
|
|
|
4760
4820
|
import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
|
|
4761
4821
|
|
|
4762
4822
|
// src/ItemPane.tsx
|
|
4763
|
-
import { useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState27 } from "react";
|
|
4823
|
+
import { Fragment as Fragment17, useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState27 } from "react";
|
|
4764
4824
|
import { DropdownMenu as DropdownMenu3, DropdownMenuContent as DropdownMenuContent3, DropdownMenuItem as DropdownMenuItem3, DropdownMenuSeparator as DropdownMenuSeparator3, DropdownMenuTrigger as DropdownMenuTrigger3 } from "@ai-matrx/design-system";
|
|
4765
4825
|
import { cn as cn12 } from "@ai-matrx/design-system";
|
|
4766
4826
|
import { Badge as Badge7, Button as Button22, CONTROLS_CONTAINER_CLASS, OptionCombobox, Switch as Switch6 } from "@ai-matrx/design-system/controls";
|
|
@@ -5142,14 +5202,12 @@ import { confirm as confirm7 } from "@ai-matrx/kit/confirm-opener";
|
|
|
5142
5202
|
import { Fragment as Fragment15, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5143
5203
|
var HANDLINGS = ["visible", "revealable", "sealed"];
|
|
5144
5204
|
var hint = (text, tone = "muted") => /* @__PURE__ */ jsx22("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
|
|
5145
|
-
var
|
|
5146
|
-
function
|
|
5147
|
-
const
|
|
5148
|
-
const env = field.envKey ?? "";
|
|
5205
|
+
var saysMore = (s, defaultHandling) => Boolean(s.envKey?.trim() || s.injectIntoSandbox || s.handling && s.handling !== defaultHandling);
|
|
5206
|
+
function FieldSettingsRows({ name, value, defaultHandling = "revealable", onChange }) {
|
|
5207
|
+
const env = value.envKey ?? "";
|
|
5149
5208
|
const envProblem = envKeyProblem(env);
|
|
5150
5209
|
const envOk = env.trim() !== "" && !envProblem;
|
|
5151
|
-
const handling =
|
|
5152
|
-
const name = field.label.trim() || "Secret";
|
|
5210
|
+
const handling = value.handling ?? defaultHandling;
|
|
5153
5211
|
const chooseHandling = async (next) => {
|
|
5154
5212
|
if (next === handling) return;
|
|
5155
5213
|
if (next === "sealed") {
|
|
@@ -5163,6 +5221,38 @@ function SecretBuilderRow({ field, onChange, onRemove }) {
|
|
|
5163
5221
|
}
|
|
5164
5222
|
onChange({ handling: next });
|
|
5165
5223
|
};
|
|
5224
|
+
return /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5225
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx22(
|
|
5226
|
+
Field8,
|
|
5227
|
+
{
|
|
5228
|
+
className: "w-full font-mono",
|
|
5229
|
+
"aria-label": `${name} env key`,
|
|
5230
|
+
"aria-invalid": Boolean(envProblem),
|
|
5231
|
+
placeholder: "e.g. GITHUB_TOKEN",
|
|
5232
|
+
autoComplete: "off",
|
|
5233
|
+
spellCheck: false,
|
|
5234
|
+
value: env,
|
|
5235
|
+
onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
|
|
5236
|
+
}
|
|
5237
|
+
) }),
|
|
5238
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ jsx22(
|
|
5239
|
+
SegmentedControl5,
|
|
5240
|
+
{
|
|
5241
|
+
"aria-label": `Who can see ${name}`,
|
|
5242
|
+
value: handling,
|
|
5243
|
+
onValueChange: (v) => void chooseHandling(v),
|
|
5244
|
+
data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
|
|
5245
|
+
}
|
|
5246
|
+
) }),
|
|
5247
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": `Use ${name} in sandbox`, checked: envOk && value.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
|
|
5248
|
+
] });
|
|
5249
|
+
}
|
|
5250
|
+
var hasSecretSettings = (s) => saysMore(s, "revealable");
|
|
5251
|
+
var hasDeclaredSettings = (s, defaultHandling) => Boolean(s && saysMore(s, defaultHandling));
|
|
5252
|
+
function SecretBuilderRow({ field, onChange, onRemove }) {
|
|
5253
|
+
const [open, setOpen] = useState22(hasSecretSettings(field));
|
|
5254
|
+
const handling = field.handling ?? "revealable";
|
|
5255
|
+
const name = field.label.trim() || "Secret";
|
|
5166
5256
|
return /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5167
5257
|
/* @__PURE__ */ jsx22(
|
|
5168
5258
|
CustomEditRow,
|
|
@@ -5170,47 +5260,26 @@ function SecretBuilderRow({ field, onChange, onRemove }) {
|
|
|
5170
5260
|
label: field.label,
|
|
5171
5261
|
value: field.value,
|
|
5172
5262
|
secret: true,
|
|
5263
|
+
multiline: field.multiline === true,
|
|
5173
5264
|
onLabel: (v) => onChange({ label: v }),
|
|
5174
5265
|
onValue: (v) => onChange({ value: v }),
|
|
5175
5266
|
onRemove,
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5267
|
+
...field.multiline ? {} : {
|
|
5268
|
+
onPasteValue: (text) => {
|
|
5269
|
+
const a = parseEnvAssignment(text);
|
|
5270
|
+
if (!a) return false;
|
|
5271
|
+
onChange({ envKey: a.key, value: a.value, ...field.label.trim() ? {} : { label: labelFromEnvKey(a.key) } });
|
|
5272
|
+
setOpen(true);
|
|
5273
|
+
return true;
|
|
5274
|
+
}
|
|
5182
5275
|
},
|
|
5183
5276
|
extra: /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5184
|
-
handling !== "sealed" ? /* @__PURE__ */ jsx22(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
|
|
5277
|
+
handling !== "sealed" && !field.multiline ? /* @__PURE__ */ jsx22(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
|
|
5185
5278
|
/* @__PURE__ */ jsx22(Button18, { variant: "quiet", icon: /* @__PURE__ */ jsx22(SlidersGlyph, {}), "aria-label": `${name} settings`, pressed: open, onClick: () => setOpen((o) => !o) })
|
|
5186
5279
|
] })
|
|
5187
5280
|
}
|
|
5188
5281
|
),
|
|
5189
|
-
open ? /* @__PURE__ */
|
|
5190
|
-
/* @__PURE__ */ jsx22(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx22(
|
|
5191
|
-
Field8,
|
|
5192
|
-
{
|
|
5193
|
-
className: "w-full font-mono",
|
|
5194
|
-
"aria-label": `${name} env key`,
|
|
5195
|
-
"aria-invalid": Boolean(envProblem),
|
|
5196
|
-
placeholder: "e.g. GITHUB_TOKEN",
|
|
5197
|
-
autoComplete: "off",
|
|
5198
|
-
spellCheck: false,
|
|
5199
|
-
value: env,
|
|
5200
|
-
onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
|
|
5201
|
-
}
|
|
5202
|
-
) }),
|
|
5203
|
-
/* @__PURE__ */ jsx22(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ jsx22(
|
|
5204
|
-
SegmentedControl5,
|
|
5205
|
-
{
|
|
5206
|
-
"aria-label": `Who can see ${name}`,
|
|
5207
|
-
value: handling,
|
|
5208
|
-
onValueChange: (v) => void chooseHandling(v),
|
|
5209
|
-
data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
|
|
5210
|
-
}
|
|
5211
|
-
) }),
|
|
5212
|
-
/* @__PURE__ */ jsx22(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": `Use ${name} in sandbox`, checked: envOk && field.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
|
|
5213
|
-
] }) : null
|
|
5282
|
+
open ? /* @__PURE__ */ jsx22(FieldSettingsRows, { name, value: field, onChange }) : null
|
|
5214
5283
|
] });
|
|
5215
5284
|
}
|
|
5216
5285
|
function withMfaMethod(custom, v) {
|
|
@@ -5839,7 +5908,9 @@ function SharingSummary({ item, port, className }) {
|
|
|
5839
5908
|
|
|
5840
5909
|
// src/ItemPane.tsx
|
|
5841
5910
|
import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
|
|
5842
|
-
import { Fragment as
|
|
5911
|
+
import { Fragment as Fragment18, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
5912
|
+
var ENV_VALUE_KEY = "env_value";
|
|
5913
|
+
var secureNoteDraft = () => ({ key: SECURE_NOTE_KEY, label: "Secure note", value: "", multiline: true, description: "Encrypted notes" });
|
|
5843
5914
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5844
5915
|
function ItemPane(props) {
|
|
5845
5916
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
@@ -6030,6 +6101,16 @@ function ItemPane(props) {
|
|
|
6030
6101
|
const fieldSettings = (f) => canEdit ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SlidersGlyph, {}), "aria-label": `${f.label} settings`, title: `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }) : null;
|
|
6031
6102
|
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
6032
6103
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
6104
|
+
const hasSecureNote = declaredKeys.has(SECURE_NOTE_KEY) || Boolean(item?.fields.some((f) => f.key === SECURE_NOTE_KEY)) || draft.secrets.some((x) => x.key === SECURE_NOTE_KEY);
|
|
6105
|
+
const [settingsToggled, setSettingsToggled] = useState27(/* @__PURE__ */ new Set());
|
|
6106
|
+
const settingsOpen = (f) => settingsToggled.has(f.key) !== (definition?.key === ENV_VALUE_KEY || hasDeclaredSettings(draft.fieldSettings?.[f.key], f.handling));
|
|
6107
|
+
const toggleSettings = (key) => setSettingsToggled((cur) => {
|
|
6108
|
+
const next = new Set(cur);
|
|
6109
|
+
if (next.has(key)) next.delete(key);
|
|
6110
|
+
else next.add(key);
|
|
6111
|
+
return next;
|
|
6112
|
+
});
|
|
6113
|
+
const patchFieldSettings = (key, p) => setDraft((d) => ({ ...d, fieldSettings: { ...d.fieldSettings, [key]: { ...d.fieldSettings?.[key], ...p } } }));
|
|
6033
6114
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
6034
6115
|
const metaValue = (key) => draft.values[key] ?? item?.custom.find((c) => c.key === key)?.value ?? "";
|
|
6035
6116
|
const extraCustom = draft.custom.filter((c) => !declaredKeys.has(c.key) && c.key !== MFA_METHOD_KEY && !isAuthenticatorStorage(c.key));
|
|
@@ -6112,7 +6193,7 @@ function ItemPane(props) {
|
|
|
6112
6193
|
/* @__PURE__ */ jsx27(SettingsIcon, { className: "size-4" }),
|
|
6113
6194
|
"Settings"
|
|
6114
6195
|
] }) : null,
|
|
6115
|
-
canManage ? /* @__PURE__ */ jsxs25(
|
|
6196
|
+
canManage ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6116
6197
|
/* @__PURE__ */ jsx27(DropdownMenuSeparator3, {}),
|
|
6117
6198
|
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
|
|
6118
6199
|
/* @__PURE__ */ jsx27(TrashGlyph, { className: "size-4" }),
|
|
@@ -6132,7 +6213,7 @@ function ItemPane(props) {
|
|
|
6132
6213
|
/* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 0 ? "This item is turned off" : offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
|
|
6133
6214
|
canTurnOn ? /* @__PURE__ */ jsx27(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
6134
6215
|
] }) : null,
|
|
6135
|
-
/* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ jsx27(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ jsx27("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ jsxs25(
|
|
6216
|
+
/* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ jsx27(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ jsx27("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6136
6217
|
/* @__PURE__ */ jsxs25(VaultSection, { children: [
|
|
6137
6218
|
mode === "new" ? /* @__PURE__ */ jsx27(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx27(
|
|
6138
6219
|
OptionCombobox,
|
|
@@ -6153,7 +6234,7 @@ function ItemPane(props) {
|
|
|
6153
6234
|
}
|
|
6154
6235
|
) }) : null,
|
|
6155
6236
|
/* @__PURE__ */ jsx27(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
|
|
6156
|
-
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs25(
|
|
6237
|
+
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6157
6238
|
/* @__PURE__ */ jsx27(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
|
|
6158
6239
|
declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ jsx27(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ jsx27(Switch6, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
|
|
6159
6240
|
] }) : null,
|
|
@@ -6162,24 +6243,29 @@ function ItemPane(props) {
|
|
|
6162
6243
|
const secretKind = f.storage === "encrypted" && f.kind === "secret";
|
|
6163
6244
|
const value = f.storage === "metadata" ? metaValue(f.key) : draft.values[f.key] ?? "";
|
|
6164
6245
|
const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6246
|
+
const newSecret = mode === "new" && f.storage === "encrypted" && owner !== "person";
|
|
6247
|
+
const open = newSecret && settingsOpen(f);
|
|
6248
|
+
return /* @__PURE__ */ jsxs25(Fragment17, { children: [
|
|
6249
|
+
/* @__PURE__ */ jsx27(
|
|
6250
|
+
EditRow,
|
|
6251
|
+
{
|
|
6252
|
+
label: f.label,
|
|
6253
|
+
value,
|
|
6254
|
+
placeholder: hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : f.required ? "Required" : isRecoveryCodesField(f) ? "Backup codes, one per line" : "",
|
|
6255
|
+
secret: secretKind,
|
|
6256
|
+
multiline: f.kind === "multiline" || value.includes("\n"),
|
|
6257
|
+
inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
|
|
6258
|
+
onChange: (v) => setValue(f.key, v),
|
|
6259
|
+
actions: /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6260
|
+
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
6261
|
+
secretKind ? /* @__PURE__ */ jsx27(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
|
|
6262
|
+
existing ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null,
|
|
6263
|
+
newSecret ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SlidersGlyph, {}), "aria-label": `${f.label} settings`, pressed: open, onClick: () => toggleSettings(f.key) }) : null
|
|
6264
|
+
] })
|
|
6265
|
+
}
|
|
6266
|
+
),
|
|
6267
|
+
open ? /* @__PURE__ */ jsx27(FieldSettingsRows, { name: f.label, value: draft.fieldSettings?.[f.key] ?? {}, defaultHandling: f.handling, onChange: (p) => patchFieldSettings(f.key, p) }) : null
|
|
6268
|
+
] }, f.key);
|
|
6183
6269
|
}),
|
|
6184
6270
|
extraFields.map((f) => /* @__PURE__ */ jsx27(
|
|
6185
6271
|
EditRow,
|
|
@@ -6188,11 +6274,11 @@ function ItemPane(props) {
|
|
|
6188
6274
|
value: draft.values[f.key] ?? "",
|
|
6189
6275
|
placeholder: f.handling === "visible" || f.key in loaded ? "" : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
6190
6276
|
secret: f.handling !== "visible" && !isRecoveryCodesField(f),
|
|
6191
|
-
multiline: isRecoveryCodesField(f),
|
|
6277
|
+
multiline: f.kind === "multiline" || isRecoveryCodesField(f) || (draft.values[f.key] ?? "").includes("\n"),
|
|
6192
6278
|
onChange: (v) => setValue(f.key, v),
|
|
6193
6279
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
6194
6280
|
removeLabel: `Delete ${f.label}`,
|
|
6195
|
-
actions: /* @__PURE__ */ jsxs25(
|
|
6281
|
+
actions: /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6196
6282
|
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
6197
6283
|
/* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
|
|
6198
6284
|
] })
|
|
@@ -6257,6 +6343,7 @@ function ItemPane(props) {
|
|
|
6257
6343
|
/* @__PURE__ */ jsx27(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(PlusGlyph, {}), children: "Add" }) }),
|
|
6258
6344
|
/* @__PURE__ */ jsxs25(DropdownMenuContent3, { align: "end", children: [
|
|
6259
6345
|
/* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
|
|
6346
|
+
!hasSecureNote ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, secureNoteDraft()] }), children: "Secure note" }) : null,
|
|
6260
6347
|
/* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
|
|
6261
6348
|
!tagsVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
|
|
6262
6349
|
!descriptionVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowDescription(true), children: "Description" }) : null,
|
|
@@ -6289,7 +6376,7 @@ function ItemPane(props) {
|
|
|
6289
6376
|
}
|
|
6290
6377
|
),
|
|
6291
6378
|
filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: true }) : mode === "new" && owner !== "person" ? /* @__PURE__ */ jsx27(DraftFilesSection, { files: queuedFiles, onFiles: setQueuedFiles }) : null
|
|
6292
|
-
] }) : item ? /* @__PURE__ */ jsxs25(
|
|
6379
|
+
] }) : item ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6293
6380
|
/* @__PURE__ */ jsxs25(VaultSection, { children: [
|
|
6294
6381
|
declared.map((f) => {
|
|
6295
6382
|
if (f.storage === "metadata") {
|
|
@@ -6344,6 +6431,13 @@ function ItemPane(props) {
|
|
|
6344
6431
|
|
|
6345
6432
|
// src/ItemList.tsx
|
|
6346
6433
|
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6434
|
+
var RECOVERY_KEYS = /^recovery_codes?$/;
|
|
6435
|
+
function otherCopyFields(item, user, secret) {
|
|
6436
|
+
if (!item.capabilities.canUse) return [];
|
|
6437
|
+
return item.fields.filter(
|
|
6438
|
+
(f) => f !== user && f !== secret && f.active !== false && f.handling !== "sealed" && (f.handling === "visible" || item.capabilities.canReveal) && !isAuthenticatorStorage(f.key) && !RECOVERY_KEYS.test(f.key)
|
|
6439
|
+
);
|
|
6440
|
+
}
|
|
6347
6441
|
var SORTS2 = [
|
|
6348
6442
|
{ value: "name", label: "Name A\u2013Z" },
|
|
6349
6443
|
{ value: "name-desc", label: "Name Z\u2013A" },
|
|
@@ -6356,7 +6450,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6356
6450
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6357
6451
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6358
6452
|
}
|
|
6359
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false }) {
|
|
6453
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems }) {
|
|
6360
6454
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6361
6455
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6362
6456
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6377,7 +6471,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6377
6471
|
}
|
|
6378
6472
|
};
|
|
6379
6473
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6380
|
-
const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
|
|
6474
|
+
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 }, i.id);
|
|
6381
6475
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6382
6476
|
return /* @__PURE__ */ jsxs26("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6383
6477
|
/* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6392,9 +6486,12 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6392
6486
|
" ",
|
|
6393
6487
|
items.length === 1 ? "item" : "items"
|
|
6394
6488
|
] }),
|
|
6395
|
-
/* @__PURE__ */ jsxs26(
|
|
6396
|
-
/* @__PURE__ */ jsx28(
|
|
6397
|
-
/* @__PURE__ */
|
|
6489
|
+
/* @__PURE__ */ jsxs26("span", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
6490
|
+
onRefresh ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(RefreshGlyph, { className: refreshing ? "animate-spin" : "" }), "aria-label": "Refresh", title: "Refresh the list", disabled: refreshing, onClick: onRefresh }) : null,
|
|
6491
|
+
/* @__PURE__ */ jsxs26(DropdownMenu4, { children: [
|
|
6492
|
+
/* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(SortGlyph, {}), "aria-label": `Sort: ${sortLabel}`, children: sortLabel }) }),
|
|
6493
|
+
/* @__PURE__ */ jsx28(DropdownMenuContent4, { align: "end", children: /* @__PURE__ */ jsx28(DropdownMenuRadioGroup, { value: sort, onValueChange: (v) => onSort(sorts.find((s) => s.value === v)?.value ?? "name"), children: sorts.map((s) => /* @__PURE__ */ jsx28(DropdownMenuRadioItem, { value: s.value, children: s.label }, s.value)) }) })
|
|
6494
|
+
] })
|
|
6398
6495
|
] })
|
|
6399
6496
|
] })
|
|
6400
6497
|
] }),
|
|
@@ -6409,7 +6506,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6409
6506
|
] }) })
|
|
6410
6507
|
] });
|
|
6411
6508
|
}
|
|
6412
|
-
function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
6509
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra }) {
|
|
6413
6510
|
const confirmed = useConfirmed();
|
|
6414
6511
|
const copy = useCopy();
|
|
6415
6512
|
const notify = useNotify();
|
|
@@ -6434,67 +6531,93 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
6434
6531
|
const copyPassword = () => secret && void run("Password", () => port.reveal(item, secret.key), true);
|
|
6435
6532
|
const copyCode = () => code && void run("One-time code", async () => (await port.authenticator.code(item)).code, true);
|
|
6436
6533
|
const copyName = () => void copy(item.name, "Name", { secret: false });
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
]
|
|
6453
|
-
}
|
|
6454
|
-
),
|
|
6455
|
-
/* @__PURE__ */ jsxs26("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
|
|
6456
|
-
user || secret ? /* @__PURE__ */ jsxs26("div", { className: cn13("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6457
|
-
user ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6458
|
-
secret ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6459
|
-
] }) : null,
|
|
6460
|
-
/* @__PURE__ */ jsxs26(DropdownMenu4, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
6461
|
-
/* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(
|
|
6462
|
-
Button23,
|
|
6534
|
+
const others = otherCopyFields(item, user, secret);
|
|
6535
|
+
const custom = canUse ? item.custom.filter((c) => c.value) : [];
|
|
6536
|
+
const hostEntries = extra?.(item) ?? [];
|
|
6537
|
+
return /* @__PURE__ */ jsxs26(
|
|
6538
|
+
"li",
|
|
6539
|
+
{
|
|
6540
|
+
className: "group relative",
|
|
6541
|
+
"data-item": item.id,
|
|
6542
|
+
onContextMenu: ownContextMenu ? (e) => {
|
|
6543
|
+
e.preventDefault();
|
|
6544
|
+
setMenuOpen(true);
|
|
6545
|
+
} : void 0,
|
|
6546
|
+
children: [
|
|
6547
|
+
/* @__PURE__ */ jsxs26(
|
|
6548
|
+
"button",
|
|
6463
6549
|
{
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
"
|
|
6467
|
-
|
|
6468
|
-
className: cn13("
|
|
6550
|
+
type: "button",
|
|
6551
|
+
"aria-current": on ? "true" : void 0,
|
|
6552
|
+
"data-surface": on ? "primary" : void 0,
|
|
6553
|
+
onClick: () => onSelect(item.id),
|
|
6554
|
+
className: cn13("flex h-12 w-full items-center gap-3 rounded-lg px-2 pr-10 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
|
|
6555
|
+
children: [
|
|
6556
|
+
/* @__PURE__ */ jsx28(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
|
|
6557
|
+
/* @__PURE__ */ jsxs26("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6558
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate text-sm font-medium", children: item.name }),
|
|
6559
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
|
|
6560
|
+
] })
|
|
6561
|
+
]
|
|
6469
6562
|
}
|
|
6470
|
-
)
|
|
6471
|
-
/* @__PURE__ */ jsxs26(
|
|
6472
|
-
user ? /* @__PURE__ */ jsxs26(
|
|
6473
|
-
/* @__PURE__ */ jsx28(
|
|
6474
|
-
"Copy ",
|
|
6475
|
-
user.label.toLowerCase()
|
|
6476
|
-
] }) : null,
|
|
6477
|
-
secret ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyPassword, children: [
|
|
6478
|
-
/* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }),
|
|
6479
|
-
"Copy password"
|
|
6480
|
-
] }) : null,
|
|
6481
|
-
code ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyCode, children: [
|
|
6482
|
-
/* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }),
|
|
6483
|
-
"Copy one-time code"
|
|
6563
|
+
),
|
|
6564
|
+
/* @__PURE__ */ jsxs26("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
|
|
6565
|
+
user || secret ? /* @__PURE__ */ jsxs26("div", { className: cn13("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6566
|
+
user ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6567
|
+
secret ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6484
6568
|
] }) : null,
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6569
|
+
/* @__PURE__ */ jsxs26(DropdownMenu4, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
6570
|
+
/* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(
|
|
6571
|
+
Button23,
|
|
6572
|
+
{
|
|
6573
|
+
variant: "quiet",
|
|
6574
|
+
icon: /* @__PURE__ */ jsx28(MoreGlyph, {}),
|
|
6575
|
+
"aria-label": `Actions for ${item.name}`,
|
|
6576
|
+
disabled: busy,
|
|
6577
|
+
className: cn13("[@media(hover:hover)]:invisible [@media(hover:hover)]:group-hover:visible [@media(hover:hover)]:group-focus-within:visible", menuOpen && "[@media(hover:hover)]:visible")
|
|
6578
|
+
}
|
|
6579
|
+
) }),
|
|
6580
|
+
/* @__PURE__ */ jsxs26(DropdownMenuContent4, { align: "end", children: [
|
|
6581
|
+
user ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyUser, children: [
|
|
6582
|
+
/* @__PURE__ */ jsx28(UserGlyph, { className: "size-4" }),
|
|
6583
|
+
"Copy ",
|
|
6584
|
+
user.label.toLowerCase()
|
|
6585
|
+
] }) : null,
|
|
6586
|
+
secret ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyPassword, children: [
|
|
6587
|
+
/* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }),
|
|
6588
|
+
"Copy password"
|
|
6589
|
+
] }) : null,
|
|
6590
|
+
code ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyCode, children: [
|
|
6591
|
+
/* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }),
|
|
6592
|
+
"Copy one-time code"
|
|
6593
|
+
] }) : null,
|
|
6594
|
+
others.map((f) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => void run(f.label, () => port.reveal(item, f.key), f.handling !== "visible"), children: [
|
|
6595
|
+
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6596
|
+
"Copy ",
|
|
6597
|
+
f.label.toLowerCase()
|
|
6598
|
+
] }, f.key)),
|
|
6599
|
+
custom.map((c) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => void copy(c.value, c.label, { secret: false }), children: [
|
|
6600
|
+
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6601
|
+
"Copy ",
|
|
6602
|
+
c.label.toLowerCase()
|
|
6603
|
+
] }, `custom:${c.key}`)),
|
|
6604
|
+
user || secret || code || others.length > 0 || custom.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6605
|
+
/* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => onSelect(item.id), children: [
|
|
6606
|
+
/* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }),
|
|
6607
|
+
"Open"
|
|
6608
|
+
] }),
|
|
6609
|
+
/* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyName, children: [
|
|
6610
|
+
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6611
|
+
"Copy name"
|
|
6612
|
+
] }),
|
|
6613
|
+
hostEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6614
|
+
hostEntries.map((h) => /* @__PURE__ */ jsx28(DropdownMenuItem4, { onSelect: h.onSelect, children: h.label }, h.label))
|
|
6615
|
+
] })
|
|
6493
6616
|
] })
|
|
6494
6617
|
] })
|
|
6495
|
-
]
|
|
6496
|
-
|
|
6497
|
-
|
|
6618
|
+
]
|
|
6619
|
+
}
|
|
6620
|
+
);
|
|
6498
6621
|
}
|
|
6499
6622
|
|
|
6500
6623
|
// src/lists/TrashView.tsx
|
|
@@ -6574,7 +6697,7 @@ function refusalText(reason) {
|
|
|
6574
6697
|
// src/lists/RestorePanel.tsx
|
|
6575
6698
|
import { useEffect as useEffect18, useState as useState29 } from "react";
|
|
6576
6699
|
import { Button as Button24 } from "@ai-matrx/design-system/controls";
|
|
6577
|
-
import { Fragment as
|
|
6700
|
+
import { Fragment as Fragment19, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
6578
6701
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6579
6702
|
function RestorePanel({ lists, item, restore, onClose }) {
|
|
6580
6703
|
const [preview, setPreview] = useState29(null);
|
|
@@ -6619,7 +6742,7 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6619
6742
|
title: `Restore "${item.name}"`,
|
|
6620
6743
|
size: "md",
|
|
6621
6744
|
onClose,
|
|
6622
|
-
footer: /* @__PURE__ */ jsxs27(
|
|
6745
|
+
footer: /* @__PURE__ */ jsxs27(Fragment19, { children: [
|
|
6623
6746
|
/* @__PURE__ */ jsx29(Button24, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
|
|
6624
6747
|
refused ? null : /* @__PURE__ */ jsx29(Button24, { variant: "primary", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
|
|
6625
6748
|
] }),
|
|
@@ -7117,7 +7240,7 @@ function addPasskeyFailure(message2) {
|
|
|
7117
7240
|
var isRevoked = (d) => d.revokedAt !== null;
|
|
7118
7241
|
|
|
7119
7242
|
// src/devices/DevicesPanel.tsx
|
|
7120
|
-
import { Fragment as
|
|
7243
|
+
import { Fragment as Fragment20, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
7121
7244
|
var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
7122
7245
|
function ErrorLine2({ text }) {
|
|
7123
7246
|
return text ? /* @__PURE__ */ jsx33("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
|
|
@@ -7248,7 +7371,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
7248
7371
|
};
|
|
7249
7372
|
const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
|
|
7250
7373
|
const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
|
|
7251
|
-
const footer = approvedUntil ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs31(
|
|
7374
|
+
const footer = approvedUntil ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs31(Fragment20, { children: [
|
|
7252
7375
|
/* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
|
|
7253
7376
|
canApprove ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
|
|
7254
7377
|
] });
|
|
@@ -7256,7 +7379,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
7256
7379
|
"This link names no key. Start again from ",
|
|
7257
7380
|
where,
|
|
7258
7381
|
"."
|
|
7259
|
-
] }) }) : /* @__PURE__ */ jsxs31(
|
|
7382
|
+
] }) }) : /* @__PURE__ */ jsxs31(Fragment20, { children: [
|
|
7260
7383
|
/* @__PURE__ */ jsxs31(VaultSection, { title: "What is asking", children: [
|
|
7261
7384
|
/* @__PURE__ */ jsx33(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
|
|
7262
7385
|
name ? /* @__PURE__ */ jsx33(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx33("span", { className: "block truncate", children: name }) }) : null,
|
|
@@ -7556,7 +7679,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7556
7679
|
}
|
|
7557
7680
|
|
|
7558
7681
|
// src/native/NativeImportPanel.tsx
|
|
7559
|
-
import { Fragment as
|
|
7682
|
+
import { Fragment as Fragment21, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7560
7683
|
var TONE = {
|
|
7561
7684
|
eligible: "success",
|
|
7562
7685
|
committed: "success",
|
|
@@ -7600,16 +7723,16 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7600
7723
|
const yes = await confirm13({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
|
|
7601
7724
|
if (yes) await flow.confirm();
|
|
7602
7725
|
};
|
|
7603
|
-
const footer = preview ? /* @__PURE__ */ jsxs32(
|
|
7726
|
+
const footer = preview ? /* @__PURE__ */ jsxs32(Fragment21, { children: [
|
|
7604
7727
|
/* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
|
|
7605
7728
|
/* @__PURE__ */ jsxs32(Button29, { variant: "primary", icon: /* @__PURE__ */ jsx34(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
|
|
7606
7729
|
"Import ",
|
|
7607
7730
|
ready
|
|
7608
7731
|
] })
|
|
7609
|
-
] }) : status ? active ? /* @__PURE__ */ jsxs32(
|
|
7732
|
+
] }) : status ? active ? /* @__PURE__ */ jsxs32(Fragment21, { children: [
|
|
7610
7733
|
/* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
|
|
7611
7734
|
/* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
|
|
7612
|
-
] }) : /* @__PURE__ */ jsxs32(
|
|
7735
|
+
] }) : /* @__PURE__ */ jsxs32(Fragment21, { children: [
|
|
7613
7736
|
/* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: flow.reset, children: "New file" }),
|
|
7614
7737
|
/* @__PURE__ */ jsx34(Button29, { variant: "primary", onClick: onClose, children: "Done" })
|
|
7615
7738
|
] }) : /* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: onClose, children: "Close" });
|
|
@@ -7648,7 +7771,7 @@ import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
|
7648
7771
|
// src/extension/CaptureCard.tsx
|
|
7649
7772
|
import { useState as useState36, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
7650
7773
|
import { Button as Button30, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
|
|
7651
|
-
import { Fragment as
|
|
7774
|
+
import { Fragment as Fragment22, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
7652
7775
|
var SEARCH_FROM = 4;
|
|
7653
7776
|
function CaptureCard({ capture, onChanged }) {
|
|
7654
7777
|
const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
|
|
@@ -7681,7 +7804,7 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7681
7804
|
] }),
|
|
7682
7805
|
/* @__PURE__ */ jsx35(Button30, { variant: "quiet", icon: /* @__PURE__ */ jsx35(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
|
|
7683
7806
|
] }),
|
|
7684
|
-
prompt.unavailable ? /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs33(
|
|
7807
|
+
prompt.unavailable ? /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs33(Fragment22, { children: [
|
|
7685
7808
|
existing.length > 0 ? /* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
|
|
7686
7809
|
existing.length >= SEARCH_FROM ? /* @__PURE__ */ jsx35(SearchField3, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
|
|
7687
7810
|
/* @__PURE__ */ jsxs33("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
|
|
@@ -7787,7 +7910,7 @@ import { useState as useState38 } from "react";
|
|
|
7787
7910
|
import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
|
|
7788
7911
|
import { Button as Button32 } from "@ai-matrx/design-system/controls";
|
|
7789
7912
|
import { CopyIcon as CopyIcon8 } from "@ai-matrx/design-system/icons";
|
|
7790
|
-
import { Fragment as
|
|
7913
|
+
import { Fragment as Fragment23, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
7791
7914
|
var HOLD_MS = 6e4;
|
|
7792
7915
|
function PageGenerator({ fields }) {
|
|
7793
7916
|
const limits = useGeneratorLimitsSource();
|
|
@@ -7838,12 +7961,12 @@ function PageGenerator({ fields }) {
|
|
|
7838
7961
|
}
|
|
7839
7962
|
};
|
|
7840
7963
|
const value = held.value;
|
|
7841
|
-
return /* @__PURE__ */ jsxs35(
|
|
7964
|
+
return /* @__PURE__ */ jsxs35(Fragment23, { children: [
|
|
7842
7965
|
/* @__PURE__ */ jsx37(
|
|
7843
7966
|
VaultRow,
|
|
7844
7967
|
{
|
|
7845
7968
|
label: "New password",
|
|
7846
|
-
actions: /* @__PURE__ */ jsxs35(
|
|
7969
|
+
actions: /* @__PURE__ */ jsxs35(Fragment23, { children: [
|
|
7847
7970
|
value ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(CopyIcon8, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
|
|
7848
7971
|
/* @__PURE__ */ jsxs35(Popover2, { open, onOpenChange: setOpen, children: [
|
|
7849
7972
|
/* @__PURE__ */ jsx37(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx37(Button32, { variant: "outline", icon: /* @__PURE__ */ jsx37(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
|
|
@@ -8121,6 +8244,7 @@ import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
|
8121
8244
|
var FULL_AT = 1120;
|
|
8122
8245
|
var SPLIT_AT = 640;
|
|
8123
8246
|
var NO_HOST = {};
|
|
8247
|
+
var FOCUS_GAP_MS = 2e3;
|
|
8124
8248
|
var ITEM_PANELS = {
|
|
8125
8249
|
share: SharePanel,
|
|
8126
8250
|
move: MovePanel,
|
|
@@ -8249,9 +8373,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8249
8373
|
const knobsRef = useRef19(host.knobs);
|
|
8250
8374
|
knobsRef.current = host.knobs;
|
|
8251
8375
|
const [signedOut, setSignedOut] = useState41(false);
|
|
8252
|
-
const
|
|
8253
|
-
|
|
8254
|
-
|
|
8376
|
+
const [refreshError, setRefreshError] = useState41(null);
|
|
8377
|
+
const [refreshing, setRefreshing] = useState41(false);
|
|
8378
|
+
const loadedAt = useRef19(0);
|
|
8379
|
+
const inFlight = useRef19(false);
|
|
8380
|
+
const apply = useCallback5(
|
|
8381
|
+
(s) => {
|
|
8382
|
+
loadedAt.current = Date.now();
|
|
8255
8383
|
setSnap(s);
|
|
8256
8384
|
setItems(s.items);
|
|
8257
8385
|
setDeleted(s.deleted);
|
|
@@ -8259,15 +8387,71 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8259
8387
|
(rows) => setDeleted([...s.deleted, ...rows.filter((r) => !s.deleted.some((d) => d.id === r.id))]),
|
|
8260
8388
|
() => void 0
|
|
8261
8389
|
);
|
|
8262
|
-
}
|
|
8390
|
+
},
|
|
8391
|
+
[port]
|
|
8392
|
+
);
|
|
8393
|
+
const refresh = useCallback5(() => {
|
|
8394
|
+
if (inFlight.current) return;
|
|
8395
|
+
inFlight.current = true;
|
|
8396
|
+
setRefreshing(true);
|
|
8397
|
+
port.load().then((s) => {
|
|
8398
|
+
setRefreshError(null);
|
|
8399
|
+
apply(s);
|
|
8400
|
+
}).catch((e) => setRefreshError(plainLoadError(e instanceof Error && e.message ? e.message : "The vault could not be read."))).finally(() => {
|
|
8401
|
+
inFlight.current = false;
|
|
8402
|
+
setRefreshing(false);
|
|
8403
|
+
});
|
|
8404
|
+
port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
|
|
8405
|
+
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
8406
|
+
}, [port, apply]);
|
|
8407
|
+
const load = useCallback5(() => {
|
|
8408
|
+
setError(null);
|
|
8409
|
+
setRefreshError(null);
|
|
8410
|
+
port.load().then(apply).catch((e) => {
|
|
8263
8411
|
setSignedOut(e?.status === 401);
|
|
8264
8412
|
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
8265
8413
|
});
|
|
8266
8414
|
port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
|
|
8267
8415
|
knobsRef.current?.().catch(() => void 0);
|
|
8268
8416
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
8269
|
-
}, [port]);
|
|
8417
|
+
}, [port, apply]);
|
|
8270
8418
|
useEffect23(load, [load]);
|
|
8419
|
+
const quietRef = useRef19({ loc, ready: false });
|
|
8420
|
+
quietRef.current = { loc, ready: snap !== null && !error };
|
|
8421
|
+
const [knobSeconds, setKnobSeconds] = useState41(null);
|
|
8422
|
+
useEffect23(() => {
|
|
8423
|
+
if (host.refreshSeconds !== void 0 || !knobsRef.current) return;
|
|
8424
|
+
let live = true;
|
|
8425
|
+
knobsRef.current().then(
|
|
8426
|
+
(r) => {
|
|
8427
|
+
const v = r["vault.list.refresh_seconds"];
|
|
8428
|
+
if (live && typeof v === "number" && v > 0) setKnobSeconds(v);
|
|
8429
|
+
},
|
|
8430
|
+
() => void 0
|
|
8431
|
+
);
|
|
8432
|
+
return () => {
|
|
8433
|
+
live = false;
|
|
8434
|
+
};
|
|
8435
|
+
}, [host.refreshSeconds]);
|
|
8436
|
+
const everySeconds = host.refreshSeconds ?? knobSeconds;
|
|
8437
|
+
useEffect23(() => {
|
|
8438
|
+
const quietly = (minGapMs) => {
|
|
8439
|
+
const { loc: here, ready } = quietRef.current;
|
|
8440
|
+
if (!ready || document.visibilityState === "hidden" || dirty.current || here.mode !== "view") return;
|
|
8441
|
+
if (Date.now() - loadedAt.current < minGapMs) return;
|
|
8442
|
+
refresh();
|
|
8443
|
+
};
|
|
8444
|
+
const onBack = () => quietly(FOCUS_GAP_MS);
|
|
8445
|
+
const onVisible = () => document.visibilityState === "visible" && onBack();
|
|
8446
|
+
window.addEventListener("focus", onBack);
|
|
8447
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
8448
|
+
const timer2 = everySeconds && everySeconds > 0 ? setInterval(() => quietly(0), everySeconds * 1e3) : null;
|
|
8449
|
+
return () => {
|
|
8450
|
+
window.removeEventListener("focus", onBack);
|
|
8451
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
8452
|
+
if (timer2) clearInterval(timer2);
|
|
8453
|
+
};
|
|
8454
|
+
}, [refresh, everySeconds]);
|
|
8271
8455
|
const inventoryRef = useRef19(onInventory);
|
|
8272
8456
|
inventoryRef.current = onInventory;
|
|
8273
8457
|
useEffect23(() => {
|
|
@@ -8433,6 +8617,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8433
8617
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8434
8618
|
canSortViewed: port.lists.recents !== void 0,
|
|
8435
8619
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8620
|
+
onRefresh: refresh,
|
|
8621
|
+
refreshing,
|
|
8622
|
+
rowContextMenu: host.rowContextMenu ?? "package",
|
|
8623
|
+
...host.rowMenuItems ? { rowMenuItems: host.rowMenuItems } : {},
|
|
8436
8624
|
...matchingIds ? { matchingIds } : {},
|
|
8437
8625
|
...compactHeader ? { header: compactHeader } : {}
|
|
8438
8626
|
}
|
|
@@ -8457,14 +8645,14 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8457
8645
|
host,
|
|
8458
8646
|
organizations: orgs,
|
|
8459
8647
|
defaultOwner: ownerDefault,
|
|
8460
|
-
seed: { name: guess?.name
|
|
8648
|
+
seed: { name: loc.name?.trim() || guess?.name || "", url: guess?.url ?? loc.url.trim() },
|
|
8461
8649
|
onBack: () => go({ kind: null }),
|
|
8462
8650
|
onMode: () => void 0,
|
|
8463
8651
|
onSaved: (item, _wasNew, n, enrolled) => {
|
|
8464
8652
|
replaceItem(item);
|
|
8465
8653
|
dirty.current = false;
|
|
8466
8654
|
if (enrolled) setFirstCode(item);
|
|
8467
|
-
move({ ...loc, itemId: item.id, mode: "view", kind: null, url: "", panel: null }, "replace");
|
|
8655
|
+
move({ ...loc, itemId: item.id, mode: "view", kind: null, url: "", name: "", panel: null }, "replace");
|
|
8468
8656
|
setNotice(n);
|
|
8469
8657
|
notify("Saved");
|
|
8470
8658
|
},
|
|
@@ -8472,7 +8660,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8472
8660
|
onDirty: (d) => {
|
|
8473
8661
|
dirty.current = d;
|
|
8474
8662
|
},
|
|
8475
|
-
onCancelNew: () => go({ mode: "view", kind: null, url: "", itemId: null }),
|
|
8663
|
+
onCancelNew: () => go({ mode: "view", kind: null, url: "", name: "", itemId: null }),
|
|
8476
8664
|
onPanel: () => void 0,
|
|
8477
8665
|
onChanged: () => void 0
|
|
8478
8666
|
},
|
|
@@ -8563,13 +8751,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8563
8751
|
const grid = mode === "full" ? "grid-cols-[15rem_21rem_minmax(0,1fr)]" : mode === "split" ? "grid-cols-[19rem_minmax(0,1fr)]" : "grid-cols-1";
|
|
8564
8752
|
const shown = panesShown(mode, specialView !== null, showingDetail);
|
|
8565
8753
|
return /* @__PURE__ */ jsxs38("div", { ref: rootRef, className: "flex h-full min-h-0 w-full flex-col bg-background text-foreground", children: [
|
|
8754
|
+
refreshError ? /* @__PURE__ */ jsxs38("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
|
|
8755
|
+
/* @__PURE__ */ jsx40("span", { className: "min-w-0 flex-1 truncate text-warning", title: refreshError, children: "Couldn\u2019t refresh. Showing what was loaded." }),
|
|
8756
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: refresh, children: "Try again" })
|
|
8757
|
+
] }) : null,
|
|
8566
8758
|
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: [
|
|
8567
8759
|
/* @__PURE__ */ jsxs38("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8568
8760
|
"Couldn\u2019t load ",
|
|
8569
8761
|
snap.unavailable.join(", "),
|
|
8570
8762
|
". Showing the rest."
|
|
8571
8763
|
] }),
|
|
8572
|
-
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick:
|
|
8764
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: refresh, children: "Try again" })
|
|
8573
8765
|
] }) : null,
|
|
8574
8766
|
/* @__PURE__ */ jsxs38("div", { className: `grid min-h-0 w-full flex-1 ${grid} overflow-hidden`, children: [
|
|
8575
8767
|
mode === "full" ? /* @__PURE__ */ jsx40(
|
|
@@ -8920,6 +9112,28 @@ function trashItem(r, ctx) {
|
|
|
8920
9112
|
createdAt: ""
|
|
8921
9113
|
};
|
|
8922
9114
|
}
|
|
9115
|
+
async function withTypes(items, door, ctx) {
|
|
9116
|
+
if (!door.schema || items.length === 0) return items;
|
|
9117
|
+
const keys = /* @__PURE__ */ new Map();
|
|
9118
|
+
const CHUNK = 100;
|
|
9119
|
+
try {
|
|
9120
|
+
for (let i = 0; i < items.length; i += CHUNK) {
|
|
9121
|
+
const ids = items.slice(i, i + CHUNK).map((x) => x.id);
|
|
9122
|
+
const { data, error } = await door.schema("users").from("credential_items").select("id,definition_key").in("id", ids);
|
|
9123
|
+
if (error) throw new Error(error.message || "credential_items read failed");
|
|
9124
|
+
for (const r of Array.isArray(data) ? data : []) {
|
|
9125
|
+
if (typeof r.id === "string" && typeof r.definition_key === "string" && r.definition_key) keys.set(r.id, r.definition_key);
|
|
9126
|
+
}
|
|
9127
|
+
}
|
|
9128
|
+
} catch (e) {
|
|
9129
|
+
console.warn("[vault] Trash item types could not be read; rows say Credential", e);
|
|
9130
|
+
return items;
|
|
9131
|
+
}
|
|
9132
|
+
return items.map((it) => {
|
|
9133
|
+
const key = keys.get(it.id);
|
|
9134
|
+
return key ? { ...it, definitionKey: key, definitionLabel: ctx.definition(key)?.label ?? humanize(key) } : it;
|
|
9135
|
+
});
|
|
9136
|
+
}
|
|
8923
9137
|
var previewOf = async (door, id) => parseRecoveryPreview(await call(door, "vault_recovery_preview", { p_id: id }));
|
|
8924
9138
|
function createListsPort(ctx, door) {
|
|
8925
9139
|
return {
|
|
@@ -8952,7 +9166,8 @@ function createListsPort(ctx, door) {
|
|
|
8952
9166
|
if (rows.length < PAGE2) break;
|
|
8953
9167
|
}
|
|
8954
9168
|
const items = all.map((r) => trashItem(r, ctx)).filter((i) => i !== null);
|
|
8955
|
-
|
|
9169
|
+
const unique = [...new Map(items.map((i) => [i.id, i])).values()];
|
|
9170
|
+
return withTypes(unique, door, ctx);
|
|
8956
9171
|
}
|
|
8957
9172
|
},
|
|
8958
9173
|
favorites: {
|
|
@@ -8975,16 +9190,25 @@ function createListsPort(ctx, door) {
|
|
|
8975
9190
|
import * as account6 from "@ai-matrx/api/account";
|
|
8976
9191
|
|
|
8977
9192
|
// src/secret-field-in.ts
|
|
8978
|
-
function
|
|
9193
|
+
function settingsIn(s) {
|
|
8979
9194
|
const envKey = s.envKey?.trim() || null;
|
|
8980
9195
|
return {
|
|
8981
|
-
field_key: fieldKeyOf(s.label),
|
|
8982
|
-
value: s.value,
|
|
8983
|
-
handling: s.handling ?? "revealable",
|
|
8984
9196
|
...envKey ? { env_key: envKey } : {},
|
|
8985
9197
|
...envKey && s.injectIntoSandbox ? { inject_into_sandbox: true } : {}
|
|
8986
9198
|
};
|
|
8987
9199
|
}
|
|
9200
|
+
function secretFieldIn(s) {
|
|
9201
|
+
return {
|
|
9202
|
+
field_key: s.key.trim() || fieldKeyOf(s.label),
|
|
9203
|
+
value: s.value,
|
|
9204
|
+
handling: s.handling ?? "revealable",
|
|
9205
|
+
...s.description ? { description: s.description } : {},
|
|
9206
|
+
...settingsIn(s)
|
|
9207
|
+
};
|
|
9208
|
+
}
|
|
9209
|
+
function declaredFieldIn(f, value, settings) {
|
|
9210
|
+
return { field_key: f.key, value, handling: settings?.handling ?? f.handling, ...settingsIn(settings ?? {}) };
|
|
9211
|
+
}
|
|
8988
9212
|
|
|
8989
9213
|
// src/sharing/api.ts
|
|
8990
9214
|
function grantOf(w) {
|
|
@@ -9085,7 +9309,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
9085
9309
|
initiation: "user",
|
|
9086
9310
|
non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
|
|
9087
9311
|
fields: [
|
|
9088
|
-
...encrypted.map((f) => (
|
|
9312
|
+
...encrypted.map((f) => declaredFieldIn(f, draft.values[f.key] ?? "", draft.fieldSettings?.[f.key])),
|
|
9089
9313
|
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn)
|
|
9090
9314
|
]
|
|
9091
9315
|
}
|
|
@@ -9214,7 +9438,7 @@ async function readNativeImportLimits(api, organizationId) {
|
|
|
9214
9438
|
var recoveryOf = (w) => w.lifecycle?.vault_recovery;
|
|
9215
9439
|
var isDeleted = (w) => recoveryOf(w)?.state === "deleted";
|
|
9216
9440
|
var MATCH_MODES2 = ["host", "domain", "exact", "never"];
|
|
9217
|
-
var FIELD_WORDS = { totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
|
|
9441
|
+
var FIELD_WORDS = { secure_notes: "Secure note", totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
|
|
9218
9442
|
var handlingOf = (v) => v === "visible" || v === "sealed" ? v : "revealable";
|
|
9219
9443
|
function fieldOf(w, def) {
|
|
9220
9444
|
const declared = def?.fields.find((f) => f.key === w.field_key);
|
|
@@ -9223,7 +9447,8 @@ function fieldOf(w, def) {
|
|
|
9223
9447
|
id: w.id,
|
|
9224
9448
|
key: w.field_key,
|
|
9225
9449
|
label: declared?.label ?? FIELD_WORDS[w.field_key] ?? humanize(w.field_key),
|
|
9226
|
-
|
|
9450
|
+
// A field no type declares still edits as several lines when its key says so (an old "Secure note").
|
|
9451
|
+
kind: declared?.kind ?? (isMultilineKey(w.field_key) ? "multiline" : handling === "visible" ? "text" : "secret"),
|
|
9227
9452
|
handling,
|
|
9228
9453
|
editable: w.editable ?? true,
|
|
9229
9454
|
envKey: w.env_key ?? null,
|
|
@@ -9378,7 +9603,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9378
9603
|
initiation: "user",
|
|
9379
9604
|
non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
|
|
9380
9605
|
fields: [
|
|
9381
|
-
...encrypted.map((f) => (
|
|
9606
|
+
...encrypted.map((f) => declaredFieldIn(f, draft.values[f.key] ?? "", draft.fieldSettings?.[f.key])),
|
|
9382
9607
|
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn),
|
|
9383
9608
|
// Backup codes on a type that does not declare them (a website login): their own encrypted field.
|
|
9384
9609
|
...!declared.some((f) => f.key === RECOVERY_CODES_KEY) && (draft.values[RECOVERY_CODES_KEY] ?? "").trim() !== "" ? [{ field_key: RECOVERY_CODES_KEY, value: parseRecoveryCodes(draft.values[RECOVERY_CODES_KEY] ?? "").join("\n"), handling: "revealable", description: "One-time account recovery codes" }] : []
|