@ai-matrx/vault 0.1.13 → 0.1.15
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 +28 -0
- package/dist/index.cjs +425 -370
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +346 -291
- package/dist/index.js.map +1 -1
- package/dist/io/csv-import.worker.js.map +1 -1
- package/dist/io/onepux.worker.js +3 -3
- package/dist/io/onepux.worker.js.map +1 -1
- package/dist/io/proton-pass.worker.js +2 -2
- package/dist/io/proton-pass.worker.js.map +1 -1
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -936,9 +936,11 @@ function inView(item, view) {
|
|
|
936
936
|
if (view.startsWith("tag:")) return item.tags.includes(view.slice(4));
|
|
937
937
|
return true;
|
|
938
938
|
}
|
|
939
|
+
var AUTHENTICATOR_WORDS = ["authenticator", "2fa", "two-factor", "two factor", "totp", "one-time password", "verification code", "2-step"];
|
|
939
940
|
function matchesQuery(item, query) {
|
|
940
941
|
const q = query.trim().toLowerCase();
|
|
941
942
|
if (!q) return true;
|
|
943
|
+
if (item.authenticator && AUTHENTICATOR_WORDS.some((w) => w === q || q.length >= 3 && w.startsWith(q))) return true;
|
|
942
944
|
return [item.name, item.definitionLabel, ...item.tags, ...item.loginUrls, ...item.custom.map((c) => `${c.label} ${c.value}`)].some((h) => h.toLowerCase().includes(q));
|
|
943
945
|
}
|
|
944
946
|
var HIDDEN_ITEM_TAG = "matrx:hidden";
|
|
@@ -1564,9 +1566,23 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
|
|
|
1564
1566
|
// src/authenticator/AuthenticatorView.tsx
|
|
1565
1567
|
var import_react13 = require("react");
|
|
1566
1568
|
var import_controls9 = require("@ai-matrx/design-system/controls");
|
|
1567
|
-
var
|
|
1569
|
+
var import_design_system10 = require("@ai-matrx/design-system");
|
|
1568
1570
|
var import_icons5 = require("@ai-matrx/design-system/icons");
|
|
1569
1571
|
|
|
1572
|
+
// src/ItemIcon.tsx
|
|
1573
|
+
var import_design_system7 = require("@ai-matrx/design-system");
|
|
1574
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1575
|
+
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
1576
|
+
const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
|
|
1577
|
+
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
1578
|
+
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
1579
|
+
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
1580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": true, className: (0, import_design_system7.cn)("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
1581
|
+
}
|
|
1582
|
+
const Glyph = definitionGlyph(definitionKey, family);
|
|
1583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": true, className: (0, import_design_system7.cn)("flex shrink-0 items-center justify-center", box, tone), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Glyph, { className: size === "lg" ? "size-5" : "size-4" }) });
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1570
1586
|
// src/authenticator/AddOtpPanel.tsx
|
|
1571
1587
|
var import_react12 = require("react");
|
|
1572
1588
|
var import_controls8 = require("@ai-matrx/design-system/controls");
|
|
@@ -1574,7 +1590,7 @@ var import_controls8 = require("@ai-matrx/design-system/controls");
|
|
|
1574
1590
|
// src/authenticator/CodeParts.tsx
|
|
1575
1591
|
var import_react8 = require("react");
|
|
1576
1592
|
var import_controls5 = require("@ai-matrx/design-system/controls");
|
|
1577
|
-
var
|
|
1593
|
+
var import_design_system8 = require("@ai-matrx/design-system");
|
|
1578
1594
|
var import_icons4 = require("@ai-matrx/design-system/icons");
|
|
1579
1595
|
var import_format5 = require("@ai-matrx/kit/format");
|
|
1580
1596
|
|
|
@@ -1677,16 +1693,16 @@ function matchIssuerToSite(issuer, candidates, siteOf) {
|
|
|
1677
1693
|
}
|
|
1678
1694
|
|
|
1679
1695
|
// src/authenticator/CodeParts.tsx
|
|
1680
|
-
var
|
|
1696
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1681
1697
|
function CountdownRing({ remaining, period, loading = false, className }) {
|
|
1682
1698
|
const r = 9.5;
|
|
1683
1699
|
const c = 2 * Math.PI * r;
|
|
1684
1700
|
const p = loading ? 0 : Math.max(0, Math.min(1, remaining / period));
|
|
1685
1701
|
const urgent = !loading && remaining <= 5;
|
|
1686
|
-
return /* @__PURE__ */ (0,
|
|
1687
|
-
/* @__PURE__ */ (0,
|
|
1688
|
-
/* @__PURE__ */ (0,
|
|
1689
|
-
/* @__PURE__ */ (0,
|
|
1702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: (0, import_design_system8.cn)("relative inline-flex size-6 shrink-0 items-center justify-center", className), role: "img", "aria-label": loading ? "Getting code" : `${remaining} seconds left`, children: [
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { viewBox: "0 0 24 24", className: "absolute inset-0 size-full -rotate-90", "aria-hidden": true, children: [
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("circle", { cx: "12", cy: "12", r, fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "text-muted" }),
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1690
1706
|
"circle",
|
|
1691
1707
|
{
|
|
1692
1708
|
cx: "12",
|
|
@@ -1703,7 +1719,7 @@ function CountdownRing({ remaining, period, loading = false, className }) {
|
|
|
1703
1719
|
}
|
|
1704
1720
|
)
|
|
1705
1721
|
] }),
|
|
1706
|
-
/* @__PURE__ */ (0,
|
|
1722
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: (0, import_design_system8.cn)("text-[10px] font-semibold leading-none tabular-nums", urgent ? "text-destructive" : "text-muted-foreground"), children: loading ? "" : remaining })
|
|
1707
1723
|
] });
|
|
1708
1724
|
}
|
|
1709
1725
|
function useCopied() {
|
|
@@ -1725,7 +1741,7 @@ function useCopied() {
|
|
|
1725
1741
|
function CodeButton({ live, digits, size = "md", label }) {
|
|
1726
1742
|
const { copied, copy } = useCopied();
|
|
1727
1743
|
const shown = live.code ? (0, import_format5.groupCode)(live.code) : maskedCode(digits);
|
|
1728
|
-
return /* @__PURE__ */ (0,
|
|
1744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1729
1745
|
"button",
|
|
1730
1746
|
{
|
|
1731
1747
|
type: "button",
|
|
@@ -1733,17 +1749,17 @@ function CodeButton({ live, digits, size = "md", label }) {
|
|
|
1733
1749
|
onClick: () => live.code && void copy(live.code),
|
|
1734
1750
|
"aria-label": live.code ? `Copy ${label} code` : `Getting ${label} code`,
|
|
1735
1751
|
title: live.code ? "Copy" : void 0,
|
|
1736
|
-
className: (0,
|
|
1752
|
+
className: (0, import_design_system8.cn)("group -mx-1.5 inline-flex max-w-full items-center gap-2.5 rounded-md px-1.5 py-1 text-left transition-colors hover:bg-accent focus-visible:bg-accent focus-visible:outline-none", size === "lg" && "gap-3"),
|
|
1737
1753
|
children: [
|
|
1738
|
-
/* @__PURE__ */ (0,
|
|
1739
|
-
copied ? /* @__PURE__ */ (0,
|
|
1754
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: (0, import_design_system8.cn)("whitespace-nowrap font-mono font-medium tabular-nums tracking-[0.08em]", size === "lg" ? "text-2xl" : "text-[1.0625rem]", live.code ? "text-foreground" : "text-disabled-foreground"), children: shown }),
|
|
1755
|
+
copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
|
|
1740
1756
|
]
|
|
1741
1757
|
}
|
|
1742
1758
|
);
|
|
1743
1759
|
}
|
|
1744
1760
|
function CopyCodeButton({ live, label }) {
|
|
1745
1761
|
const { copied, copy } = useCopied();
|
|
1746
|
-
return /* @__PURE__ */ (0,
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_controls5.Button, { variant: "quiet", icon: copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_icons4.CopyIcon, {}), ...copied ? { glyphTone: "success" } : {}, "aria-label": `Copy ${label} code`, disabled: !live.code, onClick: () => live.code && void copy(live.code) });
|
|
1747
1763
|
}
|
|
1748
1764
|
|
|
1749
1765
|
// src/authenticator/live-code.ts
|
|
@@ -1835,42 +1851,23 @@ var import_react10 = require("react");
|
|
|
1835
1851
|
var import_controls6 = require("@ai-matrx/design-system/controls");
|
|
1836
1852
|
|
|
1837
1853
|
// src/authenticator/qr.ts
|
|
1838
|
-
|
|
1839
|
-
const c = globalThis.BarcodeDetector;
|
|
1840
|
-
return typeof c === "function" ? c : null;
|
|
1841
|
-
}
|
|
1842
|
-
var support = null;
|
|
1854
|
+
var import_qr = require("@ai-matrx/capture/qr");
|
|
1843
1855
|
function canDecodeQrLocally() {
|
|
1844
|
-
if (
|
|
1845
|
-
|
|
1846
|
-
|
|
1856
|
+
if (typeof document === "undefined") return Promise.resolve(false);
|
|
1857
|
+
try {
|
|
1858
|
+
return Promise.resolve(Boolean(document.createElement("canvas").getContext("2d")));
|
|
1859
|
+
} catch {
|
|
1860
|
+
return Promise.resolve(false);
|
|
1847
1861
|
}
|
|
1848
|
-
return support;
|
|
1849
1862
|
}
|
|
1850
1863
|
function hasCamera() {
|
|
1851
1864
|
return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
|
|
1852
1865
|
}
|
|
1853
|
-
var detector = null;
|
|
1854
|
-
function qrDetector() {
|
|
1855
|
-
const C = detectorCtor();
|
|
1856
|
-
if (!C) return null;
|
|
1857
|
-
detector ??= new C({ formats: ["qr_code"] });
|
|
1858
|
-
return detector;
|
|
1859
|
-
}
|
|
1860
1866
|
async function decodeQr(source) {
|
|
1861
|
-
|
|
1862
|
-
if (!d) return null;
|
|
1863
|
-
const found = await d.detect(source);
|
|
1864
|
-
return found.find((b) => b.rawValue)?.rawValue ?? null;
|
|
1867
|
+
return (0, import_qr.decodeQrFromElement)(source);
|
|
1865
1868
|
}
|
|
1866
1869
|
async function decodeQrFile(file) {
|
|
1867
|
-
|
|
1868
|
-
const bitmap = await createImageBitmap(file);
|
|
1869
|
-
try {
|
|
1870
|
-
return await decodeQr(bitmap);
|
|
1871
|
-
} finally {
|
|
1872
|
-
bitmap.close();
|
|
1873
|
-
}
|
|
1870
|
+
return (0, import_qr.decodeQrFromImageFile)(file);
|
|
1874
1871
|
}
|
|
1875
1872
|
function imageFrom(data) {
|
|
1876
1873
|
if (!data) return null;
|
|
@@ -1885,7 +1882,7 @@ function imageFrom(data) {
|
|
|
1885
1882
|
}
|
|
1886
1883
|
|
|
1887
1884
|
// src/authenticator/Setup.tsx
|
|
1888
|
-
var
|
|
1885
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1889
1886
|
function useCanScan() {
|
|
1890
1887
|
const [ok, setOk] = (0, import_react10.useState)(false);
|
|
1891
1888
|
(0, import_react10.useEffect)(() => {
|
|
@@ -1951,15 +1948,15 @@ function QrScanPanel({ open, onResult, onClose }) {
|
|
|
1951
1948
|
stop();
|
|
1952
1949
|
};
|
|
1953
1950
|
}, [open]);
|
|
1954
|
-
return /* @__PURE__ */ (0,
|
|
1955
|
-
/* @__PURE__ */ (0,
|
|
1956
|
-
/* @__PURE__ */ (0,
|
|
1957
|
-
error ? /* @__PURE__ */ (0,
|
|
1951
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_controls6.Button, { variant: "quiet", onClick: onClose, children: "Cancel" }), children: [
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative mx-auto aspect-square w-full max-w-sm overflow-hidden rounded-xl bg-muted", children: [
|
|
1953
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("video", { ref: video, className: "size-full object-cover", playsInline: true, muted: true, "aria-label": "Camera" }),
|
|
1954
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-destructive", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
|
|
1958
1955
|
] }),
|
|
1959
|
-
/* @__PURE__ */ (0,
|
|
1956
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
|
|
1960
1957
|
] });
|
|
1961
1958
|
}
|
|
1962
|
-
function OtpSetupRow({ value, onChange, label = "
|
|
1959
|
+
function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status }) {
|
|
1963
1960
|
const file = (0, import_react10.useRef)(null);
|
|
1964
1961
|
const canScan = useCanScan();
|
|
1965
1962
|
const [scanning, setScanning] = (0, import_react10.useState)(false);
|
|
@@ -1992,11 +1989,11 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1992
1989
|
setReading(false);
|
|
1993
1990
|
}
|
|
1994
1991
|
};
|
|
1995
|
-
const end = status ? /* @__PURE__ */ (0,
|
|
1996
|
-
/* @__PURE__ */ (0,
|
|
1997
|
-
/* @__PURE__ */ (0,
|
|
1992
|
+
const end = status ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "max-w-48 truncate text-xs text-muted-foreground", children: status }) : reading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-muted-foreground", children: "Reading\u2026" }) : imageError || error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "max-w-56 truncate text-xs text-destructive", title: imageError ?? error ?? void 0, role: "alert", children: imageError ?? error }) : parsed ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex max-w-56 items-center gap-1 text-xs text-success", children: [
|
|
1993
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CheckGlyph, { className: "size-3.5 shrink-0" }),
|
|
1994
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "truncate", children: describeEnrollment(parsed) })
|
|
1998
1995
|
] }) : null;
|
|
1999
|
-
return /* @__PURE__ */ (0,
|
|
1996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2000
1997
|
"div",
|
|
2001
1998
|
{
|
|
2002
1999
|
onDragOver: (e) => {
|
|
@@ -2014,16 +2011,16 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
2014
2011
|
},
|
|
2015
2012
|
className: dragging ? "rounded-lg bg-accent" : void 0,
|
|
2016
2013
|
children: [
|
|
2017
|
-
/* @__PURE__ */ (0,
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2018
2015
|
VaultRow,
|
|
2019
2016
|
{
|
|
2020
2017
|
label,
|
|
2021
|
-
actions: /* @__PURE__ */ (0,
|
|
2022
|
-
/* @__PURE__ */ (0,
|
|
2023
|
-
canScan ? /* @__PURE__ */ (0,
|
|
2018
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2019
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_controls6.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QrGlyph, {}), "aria-label": "Choose QR image", title: "Choose or drop a QR image", disabled: disabled || reading, onClick: () => file.current?.click() }),
|
|
2020
|
+
canScan ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_controls6.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CameraGlyph, {}), "aria-label": "Scan QR code with camera", title: "Scan the site's QR code with the camera", disabled, onClick: () => setScanning(true), children: "Scan" }) : null
|
|
2024
2021
|
] }),
|
|
2025
2022
|
children: [
|
|
2026
|
-
/* @__PURE__ */ (0,
|
|
2023
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2027
2024
|
import_controls6.Field,
|
|
2028
2025
|
{
|
|
2029
2026
|
className: "w-full",
|
|
@@ -2046,7 +2043,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
2046
2043
|
end
|
|
2047
2044
|
}
|
|
2048
2045
|
),
|
|
2049
|
-
/* @__PURE__ */ (0,
|
|
2046
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2050
2047
|
"input",
|
|
2051
2048
|
{
|
|
2052
2049
|
ref: file,
|
|
@@ -2063,7 +2060,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
2063
2060
|
]
|
|
2064
2061
|
}
|
|
2065
2062
|
),
|
|
2066
|
-
canScan ? /* @__PURE__ */ (0,
|
|
2063
|
+
canScan ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2067
2064
|
QrScanPanel,
|
|
2068
2065
|
{
|
|
2069
2066
|
open: scanning,
|
|
@@ -2082,7 +2079,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
2082
2079
|
// src/authenticator/TotpRows.tsx
|
|
2083
2080
|
var import_react11 = require("react");
|
|
2084
2081
|
var import_controls7 = require("@ai-matrx/design-system/controls");
|
|
2085
|
-
var
|
|
2082
|
+
var import_design_system9 = require("@ai-matrx/design-system");
|
|
2086
2083
|
var import_confirm_opener2 = require("@ai-matrx/kit/confirm-opener");
|
|
2087
2084
|
|
|
2088
2085
|
// src/authenticator/port.ts
|
|
@@ -2094,7 +2091,7 @@ function mfaMethodOf(item) {
|
|
|
2094
2091
|
}
|
|
2095
2092
|
|
|
2096
2093
|
// src/authenticator/TotpRows.tsx
|
|
2097
|
-
var
|
|
2094
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2098
2095
|
function otpActionError(e, what) {
|
|
2099
2096
|
const status = e?.status;
|
|
2100
2097
|
if (status === 404) return "There is no one-time password here.";
|
|
@@ -2132,7 +2129,7 @@ function useOtpActions(port, item, onChanged) {
|
|
|
2132
2129
|
}),
|
|
2133
2130
|
remove: async () => {
|
|
2134
2131
|
const ok = await (0, import_confirm_opener2.confirm)({
|
|
2135
|
-
title: `Remove the
|
|
2132
|
+
title: `Remove the authenticator for ${item.name}?`,
|
|
2136
2133
|
description: "Codes stop here. Two-factor stays on at the site, and your phone app and backup codes still work.",
|
|
2137
2134
|
confirmLabel: "Remove",
|
|
2138
2135
|
variant: "destructive"
|
|
@@ -2151,38 +2148,38 @@ function TotpRow({ port, item, onChanged }) {
|
|
|
2151
2148
|
const live = useLiveCode(port, item, a.enabled && !a.removed);
|
|
2152
2149
|
const canManage = item.capabilities.canManage || item.capabilities.canEdit;
|
|
2153
2150
|
if (a.removed || !item.authenticator) return null;
|
|
2154
|
-
const menu = canManage ? /* @__PURE__ */ (0,
|
|
2155
|
-
/* @__PURE__ */ (0,
|
|
2156
|
-
/* @__PURE__ */ (0,
|
|
2157
|
-
/* @__PURE__ */ (0,
|
|
2158
|
-
/* @__PURE__ */ (0,
|
|
2151
|
+
const menu = canManage ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_design_system9.DropdownMenu, { children: [
|
|
2152
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_design_system9.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_controls7.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MoreGlyph, {}), "aria-label": "Authenticator options", disabled: a.busy }) }),
|
|
2153
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_design_system9.DropdownMenuContent, { align: "end", className: "min-w-44", children: [
|
|
2154
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_design_system9.DropdownMenuItem, { onSelect: () => void a.setEnabled(!a.enabled), children: [
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PowerGlyph, { className: "size-4" }),
|
|
2159
2156
|
a.enabled ? "Turn off" : "Turn on"
|
|
2160
2157
|
] }),
|
|
2161
|
-
/* @__PURE__ */ (0,
|
|
2162
|
-
/* @__PURE__ */ (0,
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2158
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_design_system9.DropdownMenuSeparator, {}),
|
|
2159
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_design_system9.DropdownMenuItem, { className: "text-destructive focus:text-destructive", onSelect: () => void a.remove(), children: [
|
|
2160
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TrashGlyph, { className: "size-4" }),
|
|
2164
2161
|
"Remove"
|
|
2165
2162
|
] })
|
|
2166
2163
|
] })
|
|
2167
2164
|
] }) : null;
|
|
2168
|
-
return /* @__PURE__ */ (0,
|
|
2165
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2169
2166
|
VaultRow,
|
|
2170
2167
|
{
|
|
2171
|
-
label: "
|
|
2172
|
-
actions: /* @__PURE__ */ (0,
|
|
2173
|
-
a.enabled ? /* @__PURE__ */ (0,
|
|
2168
|
+
label: "Authenticator",
|
|
2169
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2170
|
+
a.enabled ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CopyCodeButton, { live, label: item.name }) : null,
|
|
2174
2171
|
menu
|
|
2175
2172
|
] }),
|
|
2176
|
-
children: a.error ? /* @__PURE__ */ (0,
|
|
2177
|
-
/* @__PURE__ */ (0,
|
|
2178
|
-
/* @__PURE__ */ (0,
|
|
2179
|
-
] }) : !a.enabled ? /* @__PURE__ */ (0,
|
|
2180
|
-
/* @__PURE__ */ (0,
|
|
2181
|
-
canManage ? /* @__PURE__ */ (0,
|
|
2182
|
-
] }) : live.error ? /* @__PURE__ */ (0,
|
|
2183
|
-
/* @__PURE__ */ (0,
|
|
2184
|
-
/* @__PURE__ */ (0,
|
|
2185
|
-
] }) : /* @__PURE__ */ (0,
|
|
2173
|
+
children: a.error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
2174
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "truncate text-sm text-destructive", role: "alert", children: a.error }),
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_controls7.Button, { variant: "quiet", onClick: a.clearError, children: "Dismiss" })
|
|
2176
|
+
] }) : !a.enabled ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
|
|
2178
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_controls7.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PowerGlyph, {}), disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
|
|
2179
|
+
] }) : live.error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "truncate text-sm text-destructive", title: live.error, children: live.error }),
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_controls7.Button, { variant: "quiet", onClick: live.retry, children: "Retry" })
|
|
2182
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CodeButton, { live, digits: item.authenticator.digits, label: item.name })
|
|
2186
2183
|
}
|
|
2187
2184
|
);
|
|
2188
2185
|
}
|
|
@@ -2200,7 +2197,7 @@ function TotpEditRow({ value, onChange, hasExisting, item, port, onEnrolled, onR
|
|
|
2200
2197
|
setStatus(wasCancelled(e) ? null : otpActionError(e, "read that image"));
|
|
2201
2198
|
}
|
|
2202
2199
|
} : void 0;
|
|
2203
|
-
return /* @__PURE__ */ (0,
|
|
2200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2204
2201
|
OtpSetupRow,
|
|
2205
2202
|
{
|
|
2206
2203
|
value,
|
|
@@ -2225,7 +2222,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
|
|
|
2225
2222
|
const [busy, setBusy] = (0, import_react11.useState)(false);
|
|
2226
2223
|
const [error, setError] = (0, import_react11.useState)(null);
|
|
2227
2224
|
const canEdit = item.capabilities.canEdit || item.capabilities.canManage;
|
|
2228
|
-
return /* @__PURE__ */ (0,
|
|
2225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(VaultRow, { label: "Two-factor", hint: error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-destructive", children: error }) : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2229
2226
|
import_controls7.Select,
|
|
2230
2227
|
{
|
|
2231
2228
|
value: value ?? "none",
|
|
@@ -2252,7 +2249,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
|
|
|
2252
2249
|
}
|
|
2253
2250
|
|
|
2254
2251
|
// src/authenticator/AddOtpPanel.tsx
|
|
2255
|
-
var
|
|
2252
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2256
2253
|
var NEW = "__new__";
|
|
2257
2254
|
var LOGIN_KEYS = ["website_login", "username_password"];
|
|
2258
2255
|
function normalizeWebsite(raw) {
|
|
@@ -2328,23 +2325,23 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2328
2325
|
setBusy(false);
|
|
2329
2326
|
}
|
|
2330
2327
|
};
|
|
2331
|
-
if (saved) return /* @__PURE__ */ (0,
|
|
2332
|
-
return /* @__PURE__ */ (0,
|
|
2328
|
+
if (saved) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AddedPanel, { port, item: saved, onClose, onDone: () => onDone(saved.id) });
|
|
2329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2333
2330
|
Panel,
|
|
2334
2331
|
{
|
|
2335
|
-
title: "Add
|
|
2332
|
+
title: "Add authenticator",
|
|
2336
2333
|
size: "md",
|
|
2337
2334
|
onClose,
|
|
2338
|
-
footer: /* @__PURE__ */ (0,
|
|
2339
|
-
/* @__PURE__ */ (0,
|
|
2340
|
-
/* @__PURE__ */ (0,
|
|
2335
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_controls8.Button, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2337
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_controls8.Button, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
|
|
2341
2338
|
] }),
|
|
2342
2339
|
children: [
|
|
2343
|
-
/* @__PURE__ */ (0,
|
|
2344
|
-
/* @__PURE__ */ (0,
|
|
2340
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(VaultSection, { children: [
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2345
2342
|
OtpSetupRow,
|
|
2346
2343
|
{
|
|
2347
|
-
label: "Setup
|
|
2344
|
+
label: "Setup key",
|
|
2348
2345
|
value: input,
|
|
2349
2346
|
autoFocus: true,
|
|
2350
2347
|
disabled: busy,
|
|
@@ -2362,7 +2359,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2362
2359
|
status: image ? `QR image ready \xB7 ${image.name}` : null
|
|
2363
2360
|
}
|
|
2364
2361
|
),
|
|
2365
|
-
/* @__PURE__ */ (0,
|
|
2362
|
+
itemId ? null : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(VaultRow, { label: "Add to", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2366
2363
|
import_controls8.Select,
|
|
2367
2364
|
{
|
|
2368
2365
|
value: target,
|
|
@@ -2375,8 +2372,8 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2375
2372
|
}
|
|
2376
2373
|
}
|
|
2377
2374
|
) }),
|
|
2378
|
-
isNew ? /* @__PURE__ */ (0,
|
|
2379
|
-
/* @__PURE__ */ (0,
|
|
2375
|
+
isNew ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2376
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(VaultRow, { label: "Name", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2380
2377
|
import_controls8.Field,
|
|
2381
2378
|
{
|
|
2382
2379
|
className: "w-full",
|
|
@@ -2390,24 +2387,27 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2390
2387
|
"aria-label": "Name"
|
|
2391
2388
|
}
|
|
2392
2389
|
) }),
|
|
2393
|
-
/* @__PURE__ */ (0,
|
|
2390
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(VaultRow, { label: "Website", hint: websiteBad ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-destructive", children: "Not a web address" }) : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_controls8.Field, { className: "w-full", type: "url", value: website, disabled: busy || created !== null, onChange: (e) => setWebsite(e.target.value), placeholder: "example.com", "aria-label": "Website", "aria-invalid": websiteBad || void 0 }) })
|
|
2394
2391
|
] }) : null
|
|
2395
2392
|
] }),
|
|
2396
|
-
error ? /* @__PURE__ */ (0,
|
|
2393
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "px-1 text-sm text-destructive", role: "alert", children: error }) : null
|
|
2397
2394
|
]
|
|
2398
2395
|
}
|
|
2399
2396
|
);
|
|
2400
2397
|
}
|
|
2398
|
+
function FirstCodePanel(props) {
|
|
2399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AddedPanel, { ...props });
|
|
2400
|
+
}
|
|
2401
2401
|
function AddedPanel({ port, item, onClose, onDone }) {
|
|
2402
2402
|
const live = useLiveCode(port, item, true);
|
|
2403
|
-
return /* @__PURE__ */ (0,
|
|
2404
|
-
live.error ? /* @__PURE__ */ (0,
|
|
2405
|
-
/* @__PURE__ */ (0,
|
|
2403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Panel, { title: item.name, size: "sm", onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_controls8.Button, { variant: "primary", onClick: onDone, children: "Done" }), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col items-center gap-2 py-4", children: [
|
|
2404
|
+
live.error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-sm text-destructive", children: live.error }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CodeButton, { live, digits: item.authenticator?.digits ?? 6, size: "lg", label: item.name }),
|
|
2405
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: "Enter this code on the site to finish." })
|
|
2406
2406
|
] }) });
|
|
2407
2407
|
}
|
|
2408
2408
|
|
|
2409
2409
|
// src/authenticator/AuthenticatorView.tsx
|
|
2410
|
-
var
|
|
2410
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2411
2411
|
function matchesEntry(entry, q) {
|
|
2412
2412
|
if (!entry || !q) return false;
|
|
2413
2413
|
return [entry.issuer, entry.account].some((v) => v?.toLowerCase().includes(q));
|
|
@@ -2425,7 +2425,7 @@ function otpGroups(items, entries, query, hidden = /* @__PURE__ */ new Set()) {
|
|
|
2425
2425
|
const rank = (k) => k === "me" ? 0 : k === "shared" ? 2 : 1;
|
|
2426
2426
|
return [...groups.entries()].sort(([a, x], [b, y]) => rank(a) - rank(b) || x.label.localeCompare(y.label)).map(([key, g]) => ({ key, ...g }));
|
|
2427
2427
|
}
|
|
2428
|
-
function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged, header }) {
|
|
2428
|
+
function AuthenticatorView({ port, host, items, definitions, query, onOpen, onChanged, header }) {
|
|
2429
2429
|
const [entries, setEntries] = (0, import_react13.useState)(/* @__PURE__ */ new Map());
|
|
2430
2430
|
const [hidden, setHidden] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
|
|
2431
2431
|
const [adding, setAdding] = (0, import_react13.useState)(false);
|
|
@@ -2445,20 +2445,20 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2445
2445
|
const groups = otpGroups(items, entries, query, hidden);
|
|
2446
2446
|
const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
|
|
2447
2447
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
2448
|
-
return /* @__PURE__ */ (0,
|
|
2449
|
-
header ? /* @__PURE__ */ (0,
|
|
2450
|
-
/* @__PURE__ */ (0,
|
|
2451
|
-
/* @__PURE__ */ (0,
|
|
2452
|
-
/* @__PURE__ */ (0,
|
|
2453
|
-
total > 0 ? /* @__PURE__ */ (0,
|
|
2448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("section", { "aria-label": "Authenticator", className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
2449
|
+
header ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
|
|
2450
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
|
|
2451
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-w-0 items-baseline gap-2", children: [
|
|
2452
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "truncate text-sm font-semibold text-foreground", children: "Authenticator" }),
|
|
2453
|
+
total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-xs tabular-nums text-muted-foreground", children: total }) : null
|
|
2454
2454
|
] }),
|
|
2455
|
-
total > 0 ? /* @__PURE__ */ (0,
|
|
2455
|
+
total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
|
|
2456
2456
|
] }),
|
|
2457
|
-
total === 0 ? /* @__PURE__ */ (0,
|
|
2458
|
-
/* @__PURE__ */ (0,
|
|
2459
|
-
/* @__PURE__ */ (0,
|
|
2460
|
-
/* @__PURE__ */ (0,
|
|
2461
|
-
] }) : groups.length === 0 ? /* @__PURE__ */ (0,
|
|
2457
|
+
total === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
|
|
2458
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ShieldGlyph, { className: "size-6" }) }),
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
|
|
2460
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
|
|
2461
|
+
] }) : groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VaultSection, { title: g.label, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2462
2462
|
OtpListRow,
|
|
2463
2463
|
{
|
|
2464
2464
|
port,
|
|
@@ -2466,6 +2466,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2466
2466
|
family: familyOf2(item.definitionKey),
|
|
2467
2467
|
entry: entries.get(item.id),
|
|
2468
2468
|
onOpen: () => onOpen(item.id),
|
|
2469
|
+
...host.openItemInNewTab ? { onOpenInNewTab: () => host.openItemInNewTab?.(item.id) } : {},
|
|
2469
2470
|
onRename: () => {
|
|
2470
2471
|
setRenameError(null);
|
|
2471
2472
|
setRenaming(item);
|
|
@@ -2478,7 +2479,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2478
2479
|
},
|
|
2479
2480
|
item.id
|
|
2480
2481
|
)) }, g.key)) }) }),
|
|
2481
|
-
adding ? /* @__PURE__ */ (0,
|
|
2482
|
+
adding ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2482
2483
|
AddOtpPanel,
|
|
2483
2484
|
{
|
|
2484
2485
|
port,
|
|
@@ -2492,15 +2493,15 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2492
2493
|
}
|
|
2493
2494
|
}
|
|
2494
2495
|
) : null,
|
|
2495
|
-
/* @__PURE__ */ (0,
|
|
2496
|
-
|
|
2496
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2497
|
+
import_design_system10.TextInputDialog,
|
|
2497
2498
|
{
|
|
2498
2499
|
open: renaming !== null,
|
|
2499
2500
|
onOpenChange: (o) => {
|
|
2500
2501
|
if (!o && !renameBusy) setRenaming(null);
|
|
2501
2502
|
},
|
|
2502
2503
|
title: "Rename login",
|
|
2503
|
-
...renameError ? { description: /* @__PURE__ */ (0,
|
|
2504
|
+
...renameError ? { description: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-destructive", children: renameError }) } : {},
|
|
2504
2505
|
placeholder: "Login name",
|
|
2505
2506
|
defaultValue: renaming?.name ?? "",
|
|
2506
2507
|
confirmLabel: "Rename",
|
|
@@ -2523,50 +2524,53 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2523
2524
|
)
|
|
2524
2525
|
] });
|
|
2525
2526
|
}
|
|
2526
|
-
function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, onRemoved }) {
|
|
2527
|
+
function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRename, onChanged, onRemoved }) {
|
|
2527
2528
|
const a = useOtpActions(port, item, (next) => next && next.authenticator === null ? onRemoved() : onChanged());
|
|
2528
2529
|
const live = useLiveCode(port, item, a.enabled && !a.removed);
|
|
2529
2530
|
const { copy } = useCopied();
|
|
2530
|
-
const Icon = definitionGlyph(item.definitionKey, family);
|
|
2531
2531
|
const canManage = item.capabilities.canManage || item.capabilities.canEdit;
|
|
2532
2532
|
if (a.removed) return null;
|
|
2533
2533
|
const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
|
|
2534
|
-
return /* @__PURE__ */ (0,
|
|
2535
|
-
/* @__PURE__ */ (0,
|
|
2536
|
-
/* @__PURE__ */ (0,
|
|
2537
|
-
/* @__PURE__ */ (0,
|
|
2538
|
-
sub ? /* @__PURE__ */ (0,
|
|
2534
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-3 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
|
|
2535
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: onOpen, "aria-label": `Open ${item.name}`, tabIndex: -1, className: "flex size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item) || (entry?.issuer ?? "") }) }),
|
|
2536
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { type: "button", onClick: onOpen, className: "flex min-w-0 flex-col items-start rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [
|
|
2537
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: (0, import_design_system10.cn)("max-w-full truncate text-sm font-medium", a.enabled ? "text-foreground" : "text-muted-foreground"), children: item.name }),
|
|
2538
|
+
sub ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: (0, import_design_system10.cn)("max-w-full truncate text-xs", a.error ? "text-destructive" : "text-muted-foreground"), title: sub, children: sub }) : null
|
|
2539
2539
|
] }),
|
|
2540
|
-
/* @__PURE__ */ (0,
|
|
2541
|
-
/* @__PURE__ */ (0,
|
|
2542
|
-
canManage ? /* @__PURE__ */ (0,
|
|
2543
|
-
] }) : live.error ? /* @__PURE__ */ (0,
|
|
2544
|
-
/* @__PURE__ */ (0,
|
|
2545
|
-
/* @__PURE__ */ (0,
|
|
2546
|
-
] }) : /* @__PURE__ */ (0,
|
|
2547
|
-
/* @__PURE__ */ (0,
|
|
2548
|
-
/* @__PURE__ */ (0,
|
|
2549
|
-
/* @__PURE__ */ (0,
|
|
2550
|
-
/* @__PURE__ */ (0,
|
|
2551
|
-
/* @__PURE__ */ (0,
|
|
2540
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex min-w-0 justify-end", children: !a.enabled ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
2541
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
|
|
2542
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Button, { variant: "quiet", disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
|
|
2543
|
+
] }) : live.error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
2544
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "max-w-40 truncate text-xs text-destructive", title: live.error, children: live.error }),
|
|
2545
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Button, { variant: "quiet", onClick: live.retry, children: "Retry" })
|
|
2546
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CodeButton, { live, digits: item.authenticator?.digits ?? 6, label: item.name }) }),
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenu, { children: [
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_design_system10.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_controls9.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MoreGlyph, {}), "aria-label": `${item.name} options`, disabled: a.busy }) }),
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuContent, { align: "end", className: "min-w-44", children: [
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuItem, { onSelect: onOpen, children: [
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalGlyph, { className: "size-4" }),
|
|
2552
2552
|
"Open login"
|
|
2553
2553
|
] }),
|
|
2554
|
-
|
|
2555
|
-
/* @__PURE__ */ (0,
|
|
2554
|
+
onOpenInNewTab ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuItem, { onSelect: onOpenInNewTab, children: [
|
|
2555
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalGlyph, { className: "size-4" }),
|
|
2556
|
+
"Open in new tab"
|
|
2557
|
+
] }) : null,
|
|
2558
|
+
live.code ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuItem, { onSelect: () => live.code && void copy(live.code), children: [
|
|
2559
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons5.CopyIcon, { className: "size-4" }),
|
|
2556
2560
|
"Copy code"
|
|
2557
2561
|
] }) : null,
|
|
2558
|
-
canManage ? /* @__PURE__ */ (0,
|
|
2559
|
-
/* @__PURE__ */ (0,
|
|
2560
|
-
/* @__PURE__ */ (0,
|
|
2562
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
2563
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuItem, { onSelect: onRename, children: [
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PencilGlyph, { className: "size-4" }),
|
|
2561
2565
|
"Rename"
|
|
2562
2566
|
] }),
|
|
2563
|
-
/* @__PURE__ */ (0,
|
|
2564
|
-
/* @__PURE__ */ (0,
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuItem, { onSelect: () => void a.setEnabled(!a.enabled), children: [
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PowerGlyph, { className: "size-4" }),
|
|
2565
2569
|
a.enabled ? "Turn off" : "Turn on"
|
|
2566
2570
|
] }),
|
|
2567
|
-
/* @__PURE__ */ (0,
|
|
2568
|
-
/* @__PURE__ */ (0,
|
|
2569
|
-
/* @__PURE__ */ (0,
|
|
2571
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_design_system10.DropdownMenuSeparator, {}),
|
|
2572
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.DropdownMenuItem, { className: "text-destructive focus:text-destructive", onSelect: () => void a.remove(), children: [
|
|
2573
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TrashGlyph, { className: "size-4" }),
|
|
2570
2574
|
"Remove"
|
|
2571
2575
|
] })
|
|
2572
2576
|
] }) : null
|
|
@@ -2659,7 +2663,7 @@ function withoutCode(codes, index) {
|
|
|
2659
2663
|
}
|
|
2660
2664
|
|
|
2661
2665
|
// src/fields/SettingsPanels.tsx
|
|
2662
|
-
var
|
|
2666
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2663
2667
|
var say = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
2664
2668
|
function useSaver(onChanged) {
|
|
2665
2669
|
const [busy, setBusy] = (0, import_react14.useState)(null);
|
|
@@ -2681,14 +2685,14 @@ function useSaver(onChanged) {
|
|
|
2681
2685
|
return { busy, error, setError, save };
|
|
2682
2686
|
}
|
|
2683
2687
|
function Problem({ children }) {
|
|
2684
|
-
return /* @__PURE__ */ (0,
|
|
2688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children });
|
|
2685
2689
|
}
|
|
2686
|
-
var quietHint = (text, tone = "muted") => /* @__PURE__ */ (0,
|
|
2690
|
+
var quietHint = (text, tone = "muted") => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
|
|
2687
2691
|
function FieldSettingsPanel(props) {
|
|
2688
2692
|
const field = props.item.fields.find((f) => f.id === props.arg);
|
|
2689
2693
|
if (!field)
|
|
2690
|
-
return /* @__PURE__ */ (0,
|
|
2691
|
-
return /* @__PURE__ */ (0,
|
|
2694
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Panel, { title: "Field settings", size: "md", onClose: props.onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "primary", onClick: props.onClose, children: "Done" }), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Empty, { children: "This field is no longer on the item." }) });
|
|
2695
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(FieldSettings, { ...props, field }, field.id);
|
|
2692
2696
|
}
|
|
2693
2697
|
function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
2694
2698
|
const { busy, error, setError, save } = useSaver((next) => onChanged(next));
|
|
@@ -2727,9 +2731,9 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2727
2731
|
};
|
|
2728
2732
|
const handling = HANDLING_WORDS[field.handling];
|
|
2729
2733
|
const locked = !canEdit || busy !== null;
|
|
2730
|
-
return /* @__PURE__ */ (0,
|
|
2731
|
-
!canEdit ? /* @__PURE__ */ (0,
|
|
2732
|
-
/* @__PURE__ */ (0,
|
|
2734
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Panel, { title: `${field.label} settings`, size: "md", onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "primary", onClick: onClose, children: "Done" }), children: [
|
|
2735
|
+
!canEdit ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
|
|
2736
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultSection, { title: "Who can see it", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Value", hint: quietHint(handling.hint), children: field.handling === "sealed" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Badge, { icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LockGlyph, {}), children: "Sealed for good" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2733
2737
|
import_controls10.SegmentedControl,
|
|
2734
2738
|
{
|
|
2735
2739
|
"aria-label": "Who can see it",
|
|
@@ -2738,8 +2742,8 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2738
2742
|
data: handlingChoices(field.handling).map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint, disabled: locked }))
|
|
2739
2743
|
}
|
|
2740
2744
|
) }) }),
|
|
2741
|
-
/* @__PURE__ */ (0,
|
|
2742
|
-
/* @__PURE__ */ (0,
|
|
2745
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(VaultSection, { title: "Automation", children: [
|
|
2746
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Env key", hint: envProblem ? quietHint(envProblem, "destructive") : quietHint("The name sandboxes and workflows use"), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2743
2747
|
import_controls10.Field,
|
|
2744
2748
|
{
|
|
2745
2749
|
ref: envRef,
|
|
@@ -2759,10 +2763,10 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2759
2763
|
}
|
|
2760
2764
|
}
|
|
2761
2765
|
) }),
|
|
2762
|
-
/* @__PURE__ */ (0,
|
|
2766
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Use in sandbox", hint: blocker && !field.injectIntoSandbox ? quietHint(blocker) : quietHint("Sandboxes get it as an env variable"), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Switch, { "aria-label": "Use in sandbox", checked: field.injectIntoSandbox, disabled: locked, onCheckedChange: (v) => void setSandbox(v) }) })
|
|
2763
2767
|
] }),
|
|
2764
|
-
/* @__PURE__ */ (0,
|
|
2765
|
-
/* @__PURE__ */ (0,
|
|
2768
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(VaultSection, { title: "Field", children: [
|
|
2769
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Description", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2766
2770
|
import_controls10.Field,
|
|
2767
2771
|
{
|
|
2768
2772
|
className: "w-full",
|
|
@@ -2778,10 +2782,10 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2778
2782
|
}
|
|
2779
2783
|
}
|
|
2780
2784
|
) }),
|
|
2781
|
-
/* @__PURE__ */ (0,
|
|
2782
|
-
/* @__PURE__ */ (0,
|
|
2785
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Editable", hint: quietHint(field.editable ? "The value can be changed" : "The value is locked"), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Switch, { "aria-label": "Editable", checked: field.editable, disabled: locked, onCheckedChange: (v) => void update("editable", { editable: v }) }) }),
|
|
2786
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Turned on", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Switch, { "aria-label": "Turned on", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: v }) }) })
|
|
2783
2787
|
] }),
|
|
2784
|
-
error ? /* @__PURE__ */ (0,
|
|
2788
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Problem, { children: error }) : null
|
|
2785
2789
|
] });
|
|
2786
2790
|
}
|
|
2787
2791
|
function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
@@ -2808,10 +2812,10 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2808
2812
|
});
|
|
2809
2813
|
};
|
|
2810
2814
|
const fillHint = !hasWebsite ? "Add a website first" : item.browserFillEnabled ? "Offered on matching pages" : "Never filled automatically";
|
|
2811
|
-
return /* @__PURE__ */ (0,
|
|
2812
|
-
!canEdit ? /* @__PURE__ */ (0,
|
|
2813
|
-
/* @__PURE__ */ (0,
|
|
2814
|
-
/* @__PURE__ */ (0,
|
|
2815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Panel, { title: "Item settings", size: "md", onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "primary", onClick: onClose, children: "Done" }), children: [
|
|
2816
|
+
!canEdit ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
|
|
2817
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(VaultSection, { title: "In the browser", children: [
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Website matching", hint: quietHint(MATCH_WORDS[item.uriMatchMode].hint), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2815
2819
|
import_controls10.Select,
|
|
2816
2820
|
{
|
|
2817
2821
|
"aria-label": "Website matching",
|
|
@@ -2821,45 +2825,45 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2821
2825
|
onValueChange: (m) => void save("match", () => port.fields.updateItem(item, { uriMatchMode: m }))
|
|
2822
2826
|
}
|
|
2823
2827
|
) }),
|
|
2824
|
-
/* @__PURE__ */ (0,
|
|
2825
|
-
promotable.map((f) => /* @__PURE__ */ (0,
|
|
2828
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultRow, { label: "Fill in browser", hint: quietHint(fillHint), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Switch, { "aria-label": "Fill in browser", checked: hasWebsite && item.browserFillEnabled, disabled: locked || !hasWebsite, onCheckedChange: (v) => void save("fill", () => port.fields.updateItem(item, { browserFillEnabled: v })) }) }),
|
|
2829
|
+
promotable.map((f) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2826
2830
|
VaultRow,
|
|
2827
2831
|
{
|
|
2828
2832
|
label: f.label,
|
|
2829
2833
|
hint: quietHint("Encrypted, so the browser can\u2019t match it"),
|
|
2830
|
-
actions: /* @__PURE__ */ (0,
|
|
2831
|
-
children: /* @__PURE__ */ (0,
|
|
2834
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons6.GlobeIcon, {}), disabled: locked, onClick: () => void promote(f), children: "Use as website" }),
|
|
2835
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-muted-foreground", children: "Not a website yet" })
|
|
2832
2836
|
},
|
|
2833
2837
|
f.id
|
|
2834
2838
|
))
|
|
2835
2839
|
] }),
|
|
2836
|
-
/* @__PURE__ */ (0,
|
|
2837
|
-
/* @__PURE__ */ (0,
|
|
2838
|
-
advanced ? /* @__PURE__ */ (0,
|
|
2840
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
2841
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.DisclosureHeader, { open: advanced, title: "Advanced", meta: item.fields.length ? `${item.fields.length} fields` : void 0, onClick: () => setAdvanced((a) => !a) }),
|
|
2842
|
+
advanced ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VaultSection, { children: item.fields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Empty, { children: "No encrypted fields." }) : item.fields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2839
2843
|
VaultRow,
|
|
2840
2844
|
{
|
|
2841
2845
|
label: f.label,
|
|
2842
|
-
actions: /* @__PURE__ */ (0,
|
|
2843
|
-
children: /* @__PURE__ */ (0,
|
|
2844
|
-
/* @__PURE__ */ (0,
|
|
2845
|
-
f.envKey ? /* @__PURE__ */ (0,
|
|
2846
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SlidersGlyph, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }),
|
|
2847
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "block truncate", children: [
|
|
2848
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: f.handling === "sealed" ? "text-foreground" : "text-muted-foreground", children: HANDLING_WORDS[f.handling].label }),
|
|
2849
|
+
f.envKey ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "font-mono text-muted-foreground", children: [
|
|
2846
2850
|
" \xB7 ",
|
|
2847
2851
|
f.envKey
|
|
2848
2852
|
] }) : null,
|
|
2849
|
-
f.injectIntoSandbox ? /* @__PURE__ */ (0,
|
|
2850
|
-
!f.active ? /* @__PURE__ */ (0,
|
|
2853
|
+
f.injectIntoSandbox ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
|
|
2854
|
+
!f.active ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
|
|
2851
2855
|
] })
|
|
2852
2856
|
},
|
|
2853
2857
|
f.id
|
|
2854
2858
|
)) }) : null
|
|
2855
2859
|
] }),
|
|
2856
|
-
error ? /* @__PURE__ */ (0,
|
|
2860
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Problem, { children: error }) : null
|
|
2857
2861
|
] });
|
|
2858
2862
|
}
|
|
2859
2863
|
|
|
2860
2864
|
// src/generator/PasswordGenerator.tsx
|
|
2861
2865
|
var import_react15 = require("react");
|
|
2862
|
-
var
|
|
2866
|
+
var import_design_system11 = require("@ai-matrx/design-system");
|
|
2863
2867
|
var import_controls11 = require("@ai-matrx/design-system/controls");
|
|
2864
2868
|
var import_icons7 = require("@ai-matrx/design-system/icons");
|
|
2865
2869
|
|
|
@@ -2916,10 +2920,10 @@ function strengthOf(bits) {
|
|
|
2916
2920
|
}
|
|
2917
2921
|
|
|
2918
2922
|
// src/generator/PasswordGenerator.tsx
|
|
2919
|
-
var
|
|
2923
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2920
2924
|
var LimitsCtx = (0, import_react15.createContext)(null);
|
|
2921
2925
|
function GeneratorLimitsProvider({ resolve: resolve2, children }) {
|
|
2922
|
-
return /* @__PURE__ */ (0,
|
|
2926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(LimitsCtx.Provider, { value: resolve2 ?? null, children });
|
|
2923
2927
|
}
|
|
2924
2928
|
function useGeneratorLimitsSource() {
|
|
2925
2929
|
return (0, import_react15.useContext)(LimitsCtx);
|
|
@@ -2980,11 +2984,11 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2980
2984
|
(0, import_react15.useEffect)(() => () => {
|
|
2981
2985
|
if (expiry.current) clearTimeout(expiry.current);
|
|
2982
2986
|
}, []);
|
|
2983
|
-
if (limits.state === "loading") return /* @__PURE__ */ (0,
|
|
2987
|
+
if (limits.state === "loading") return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "px-1 py-3 text-sm text-muted-foreground", "aria-live": "polite", children: "Reading limits\u2026" });
|
|
2984
2988
|
if (limits.state === "unavailable")
|
|
2985
|
-
return /* @__PURE__ */ (0,
|
|
2986
|
-
/* @__PURE__ */ (0,
|
|
2987
|
-
/* @__PURE__ */ (0,
|
|
2989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-2 px-1 py-2", children: [
|
|
2990
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { role: "alert", className: "text-sm text-destructive", children: limits.message }),
|
|
2991
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RefreshGlyph, {}), onClick: () => setRound((n) => n + 1), children: "Try again" })
|
|
2988
2992
|
] });
|
|
2989
2993
|
const ceilings = limits.limits;
|
|
2990
2994
|
const change = (next) => make(next, ceilings);
|
|
@@ -3001,8 +3005,8 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
3001
3005
|
drop();
|
|
3002
3006
|
onUse(value);
|
|
3003
3007
|
};
|
|
3004
|
-
return /* @__PURE__ */ (0,
|
|
3005
|
-
/* @__PURE__ */ (0,
|
|
3008
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex w-full flex-col gap-3", "aria-label": "Password generator", children: [
|
|
3009
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3006
3010
|
import_controls11.SegmentedControl,
|
|
3007
3011
|
{
|
|
3008
3012
|
fill: true,
|
|
@@ -3012,24 +3016,24 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
3012
3016
|
data: [{ value: "password", label: "Password" }, { value: "passphrase", label: "Passphrase" }]
|
|
3013
3017
|
}
|
|
3014
3018
|
),
|
|
3015
|
-
/* @__PURE__ */ (0,
|
|
3016
|
-
/* @__PURE__ */ (0,
|
|
3017
|
-
/* @__PURE__ */ (0,
|
|
3018
|
-
/* @__PURE__ */ (0,
|
|
3019
|
-
/* @__PURE__ */ (0,
|
|
3020
|
-
/* @__PURE__ */ (0,
|
|
3019
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1 rounded-lg bg-muted px-3 py-2", children: [
|
|
3020
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex min-h-7 items-start gap-1", children: [
|
|
3021
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("code", { className: (0, import_design_system11.cn)("min-w-0 flex-1 break-all py-1 font-mono text-sm", candidate ? "text-foreground" : "text-muted-foreground"), "data-testid": "generated-value", children: candidate ? revealed ? candidate.value : MASK3 : "\u2014" }),
|
|
3022
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "quiet", icon: revealed ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(EyeOffGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(EyeGlyph, {}), "aria-label": revealed ? "Hide" : "Reveal", disabled: !candidate, onClick: () => setRevealed((r) => !r) }),
|
|
3023
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons7.CopyIcon, {}), "aria-label": "Copy", disabled: !candidate, onClick: () => void copy() }),
|
|
3024
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RefreshGlyph, {}), "aria-label": "Generate another", onClick: () => change(settings) })
|
|
3021
3025
|
] }),
|
|
3022
|
-
strength && candidate ? /* @__PURE__ */ (0,
|
|
3023
|
-
/* @__PURE__ */ (0,
|
|
3024
|
-
/* @__PURE__ */ (0,
|
|
3026
|
+
strength && candidate ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "text-xs", children: [
|
|
3027
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: (0, import_design_system11.cn)(strength.tone === "success" && "text-success", strength.tone === "primary" && "text-primary", strength.tone === "warning" && "text-warning"), children: strength.label }),
|
|
3028
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
3025
3029
|
" \xB7 ",
|
|
3026
3030
|
Math.floor(candidate.bits),
|
|
3027
3031
|
"-bit"
|
|
3028
3032
|
] })
|
|
3029
3033
|
] }) : null
|
|
3030
3034
|
] }),
|
|
3031
|
-
settings.kind === "password" ? /* @__PURE__ */ (0,
|
|
3032
|
-
/* @__PURE__ */ (0,
|
|
3035
|
+
settings.kind === "password" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
3036
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label: "Length", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.NumberStepper, { value: settings.password.length, min: minPasswordLength(settings.password), max: ceilings.maxPasswordLength, fallback: 24, onChange: (length) => setPassword({ length }) }) }),
|
|
3033
3037
|
[
|
|
3034
3038
|
["lowercase", "Lowercase"],
|
|
3035
3039
|
["uppercase", "Uppercase"],
|
|
@@ -3038,26 +3042,26 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
3038
3042
|
].map(([key, label]) => {
|
|
3039
3043
|
const on = settings.password[key];
|
|
3040
3044
|
const last = on && minPasswordLength(settings.password) === 1;
|
|
3041
|
-
return /* @__PURE__ */ (0,
|
|
3045
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Switch, { "aria-label": label, checked: on, disabled: last, onCheckedChange: (v) => setPassword({ [key]: v }) }) }, key);
|
|
3042
3046
|
}),
|
|
3043
|
-
/* @__PURE__ */ (0,
|
|
3044
|
-
] }) : /* @__PURE__ */ (0,
|
|
3045
|
-
/* @__PURE__ */ (0,
|
|
3046
|
-
/* @__PURE__ */ (0,
|
|
3047
|
-
/* @__PURE__ */ (0,
|
|
3048
|
-
/* @__PURE__ */ (0,
|
|
3047
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label: "Avoid look-alikes", hint: "No 0/O, 1/l/I", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Switch, { "aria-label": "Avoid look-alikes", checked: settings.password.excludeAmbiguous, onCheckedChange: (v) => setPassword({ excludeAmbiguous: v }) }) })
|
|
3048
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label: "Words", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.NumberStepper, { value: settings.passphrase.wordCount, min: MIN_PASSPHRASE_WORDS, max: ceilings.maxPassphraseWords, fallback: MIN_PASSPHRASE_WORDS, onChange: (wordCount) => change({ ...settings, passphrase: { ...settings.passphrase, wordCount } }) }) }),
|
|
3050
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label: "Separator", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Select, { "aria-label": "Separator", variant: "inline", align: "end", value: settings.passphrase.separator, options: SEPARATORS, onValueChange: (separator) => change({ ...settings, passphrase: { ...settings.passphrase, separator } }) }) }),
|
|
3051
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label: "Capitalize", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Switch, { "aria-label": "Capitalize", checked: settings.passphrase.capitalize, onCheckedChange: (capitalize) => change({ ...settings, passphrase: { ...settings.passphrase, capitalize } }) }) }),
|
|
3052
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OptionLine, { label: "Add a digit", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Switch, { "aria-label": "Add a digit", checked: settings.passphrase.appendDigit, onCheckedChange: (appendDigit) => change({ ...settings, passphrase: { ...settings.passphrase, appendDigit } }) }) })
|
|
3049
3053
|
] }),
|
|
3050
|
-
note ? /* @__PURE__ */ (0,
|
|
3051
|
-
/* @__PURE__ */ (0,
|
|
3054
|
+
note ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { "aria-live": "polite", className: (0, import_design_system11.cn)("text-xs", note.tone === "destructive" ? "text-destructive" : note.tone === "success" ? "text-success" : "text-muted-foreground"), children: note.text }) : null,
|
|
3055
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "primary", disabled: !candidate, onClick: use, children: useLabel })
|
|
3052
3056
|
] });
|
|
3053
3057
|
}
|
|
3054
3058
|
function OptionLine({ label, hint, children }) {
|
|
3055
|
-
return /* @__PURE__ */ (0,
|
|
3056
|
-
/* @__PURE__ */ (0,
|
|
3057
|
-
/* @__PURE__ */ (0,
|
|
3058
|
-
hint ? /* @__PURE__ */ (0,
|
|
3059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex min-h-9 items-center justify-between gap-3", children: [
|
|
3060
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex min-w-0 flex-col", children: [
|
|
3061
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-sm text-foreground", children: label }),
|
|
3062
|
+
hint ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: hint }) : null
|
|
3059
3063
|
] }),
|
|
3060
|
-
/* @__PURE__ */ (0,
|
|
3064
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex shrink-0 items-center", children })
|
|
3061
3065
|
] });
|
|
3062
3066
|
}
|
|
3063
3067
|
function GenerateButton({ onUse, label, limits, disabled }) {
|
|
@@ -3066,9 +3070,9 @@ function GenerateButton({ onUse, label, limits, disabled }) {
|
|
|
3066
3070
|
const [open, setOpen] = (0, import_react15.useState)(false);
|
|
3067
3071
|
if (!source) return null;
|
|
3068
3072
|
const name = label ?? "Generate password";
|
|
3069
|
-
return /* @__PURE__ */ (0,
|
|
3070
|
-
/* @__PURE__ */ (0,
|
|
3071
|
-
/* @__PURE__ */ (0,
|
|
3073
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system11.Popover, { open, onOpenChange: setOpen, children: [
|
|
3074
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system11.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(KeyGlyph, {}), "aria-label": name, title: name, disabled }) }),
|
|
3075
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system11.PopoverContent, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3072
3076
|
PasswordGenerator,
|
|
3073
3077
|
{
|
|
3074
3078
|
limits: source,
|
|
@@ -3238,23 +3242,23 @@ function startNewRestoreRun(preview) {
|
|
|
3238
3242
|
|
|
3239
3243
|
// src/io/lines.tsx
|
|
3240
3244
|
var import_react17 = require("react");
|
|
3241
|
-
var
|
|
3245
|
+
var import_design_system12 = require("@ai-matrx/design-system");
|
|
3242
3246
|
var import_controls12 = require("@ai-matrx/design-system/controls");
|
|
3243
|
-
var
|
|
3247
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3244
3248
|
function PickLine({ checked, onChange, disabled = false, title, detail, badge, tone }) {
|
|
3245
|
-
return /* @__PURE__ */ (0,
|
|
3246
|
-
/* @__PURE__ */ (0,
|
|
3247
|
-
/* @__PURE__ */ (0,
|
|
3248
|
-
detail ? /* @__PURE__ */ (0,
|
|
3249
|
-
badge ? /* @__PURE__ */ (0,
|
|
3249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex min-h-11 items-center gap-3 px-4 py-1", "data-clickable": disabled ? void 0 : "", children: [
|
|
3250
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_design_system12.Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
|
|
3251
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: title }),
|
|
3252
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hidden min-w-0 max-w-[45%] truncate text-xs text-muted-foreground sm:block", children: detail }) : null,
|
|
3253
|
+
badge ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_controls12.Badge, { tone: tone ?? "neutral", children: badge }) : null
|
|
3250
3254
|
] });
|
|
3251
3255
|
}
|
|
3252
3256
|
function Windowed({ items, size = 150, render }) {
|
|
3253
3257
|
const [all, setAll] = (0, import_react17.useState)(false);
|
|
3254
3258
|
const shown = all ? items : items.slice(0, size);
|
|
3255
|
-
return /* @__PURE__ */ (0,
|
|
3259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
3256
3260
|
shown.map(render),
|
|
3257
|
-
items.length > shown.length ? /* @__PURE__ */ (0,
|
|
3261
|
+
items.length > shown.length ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "px-4 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_controls12.Button, { variant: "quiet", onClick: () => setAll(true), children: [
|
|
3258
3262
|
"Show all ",
|
|
3259
3263
|
items.length
|
|
3260
3264
|
] }) }) : null
|
|
@@ -3262,18 +3266,18 @@ function Windowed({ items, size = 150, render }) {
|
|
|
3262
3266
|
}
|
|
3263
3267
|
function More({ title = "More", children }) {
|
|
3264
3268
|
const [open, setOpen] = (0, import_react17.useState)(false);
|
|
3265
|
-
return /* @__PURE__ */ (0,
|
|
3266
|
-
/* @__PURE__ */ (0,
|
|
3269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
3270
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_controls12.DisclosureHeader, { open, title, onClick: () => setOpen((o) => !o) }),
|
|
3267
3271
|
open ? children : null
|
|
3268
3272
|
] });
|
|
3269
3273
|
}
|
|
3270
3274
|
function ErrorLine({ message: message2 }) {
|
|
3271
|
-
return message2 ? /* @__PURE__ */ (0,
|
|
3275
|
+
return message2 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children: message2 }) : null;
|
|
3272
3276
|
}
|
|
3273
3277
|
var plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
3274
3278
|
|
|
3275
3279
|
// src/io/BackupPanel.tsx
|
|
3276
|
-
var
|
|
3280
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3277
3281
|
var RECORD_STATUS = {
|
|
3278
3282
|
created: "Restored",
|
|
3279
3283
|
replayed: "Already restored",
|
|
@@ -3285,17 +3289,17 @@ function omissionText(o) {
|
|
|
3285
3289
|
return `${o.count ?? "Some"} ${what}: ${o.reason.replaceAll("_", " ")}`;
|
|
3286
3290
|
}
|
|
3287
3291
|
function Summary({ value }) {
|
|
3288
|
-
return /* @__PURE__ */ (0,
|
|
3289
|
-
/* @__PURE__ */ (0,
|
|
3290
|
-
/* @__PURE__ */ (0,
|
|
3291
|
-
/* @__PURE__ */ (0,
|
|
3292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { children: [
|
|
3293
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Credentials", children: value.record_count }),
|
|
3294
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Protected fields", children: value.field_count }),
|
|
3295
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Files", children: value.attachment_count > 0 ? `${value.attachment_count} \xB7 ${(0, import_format6.formatFileSize)(value.attachment_bytes)}` : "0" })
|
|
3292
3296
|
] });
|
|
3293
3297
|
}
|
|
3294
3298
|
function Omissions({ omissions, accepted, onAccepted, verb }) {
|
|
3295
3299
|
if (omissions.length === 0) return null;
|
|
3296
|
-
return /* @__PURE__ */ (0,
|
|
3297
|
-
omissions.map((o, i) => /* @__PURE__ */ (0,
|
|
3298
|
-
/* @__PURE__ */ (0,
|
|
3300
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { title: "Left out", children: [
|
|
3301
|
+
omissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: o.component.replaceAll("_", " "), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "block truncate text-muted-foreground", title: omissionText(o), children: omissionText(o) }) }, `${o.component}-${o.source_item_id ?? i}`)),
|
|
3302
|
+
/* @__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` }) })
|
|
3299
3303
|
] });
|
|
3300
3304
|
}
|
|
3301
3305
|
function BackupPanel({ port, items, onClose, onChanged }) {
|
|
@@ -3401,21 +3405,21 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3401
3405
|
const retryable = (result?.retryable_failure ?? 0) > 0;
|
|
3402
3406
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3403
3407
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3404
|
-
const footer = mode === "backup" ? /* @__PURE__ */ (0,
|
|
3405
|
-
/* @__PURE__ */ (0,
|
|
3406
|
-
backup ? /* @__PURE__ */ (0,
|
|
3408
|
+
const footer = mode === "backup" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3409
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3410
|
+
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: [
|
|
3407
3411
|
"Review ",
|
|
3408
3412
|
selected.size
|
|
3409
3413
|
] })
|
|
3410
|
-
] }) : /* @__PURE__ */ (0,
|
|
3411
|
-
/* @__PURE__ */ (0,
|
|
3412
|
-
result ? retryable ? /* @__PURE__ */ (0,
|
|
3414
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3415
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
|
|
3416
|
+
result ? retryable ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "primary", disabled: busy, onClick: () => void restore(), children: "Try again" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "outline", disabled: busy, onClick: () => void again(), children: "Restore again" }) : restorePreview ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_controls13.Button, { variant: "primary", disabled: busy || restorePreview.omissions.length > 0 && !accepted, onClick: () => void restore(), children: [
|
|
3413
3417
|
"Restore ",
|
|
3414
3418
|
restorePreview.record_count
|
|
3415
|
-
] }) : /* @__PURE__ */ (0,
|
|
3419
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "primary", disabled: busy || !file || !passphrase, onClick: () => void reviewRestore(), children: "Review" })
|
|
3416
3420
|
] });
|
|
3417
|
-
return /* @__PURE__ */ (0,
|
|
3418
|
-
/* @__PURE__ */ (0,
|
|
3421
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Panel, { title: "Backup", size: "lg", onClose, footer, children: [
|
|
3422
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3419
3423
|
import_controls13.SegmentedControl,
|
|
3420
3424
|
{
|
|
3421
3425
|
value: mode,
|
|
@@ -3428,36 +3432,36 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3428
3432
|
]
|
|
3429
3433
|
}
|
|
3430
3434
|
),
|
|
3431
|
-
mode === "backup" ? /* @__PURE__ */ (0,
|
|
3432
|
-
/* @__PURE__ */ (0,
|
|
3435
|
+
mode === "backup" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3436
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3433
3437
|
VaultSection,
|
|
3434
3438
|
{
|
|
3435
3439
|
title: `${selected.size} of ${plural(items.length, "credential")}`,
|
|
3436
|
-
actions: /* @__PURE__ */ (0,
|
|
3437
|
-
/* @__PURE__ */ (0,
|
|
3440
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3441
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
|
|
3438
3442
|
setBackup(null);
|
|
3439
3443
|
setSelected(new Set(items.map((i) => i.id)));
|
|
3440
3444
|
}, children: "All" }),
|
|
3441
|
-
/* @__PURE__ */ (0,
|
|
3445
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
|
|
3442
3446
|
setBackup(null);
|
|
3443
3447
|
setSelected(/* @__PURE__ */ new Set());
|
|
3444
3448
|
}, children: "None" })
|
|
3445
3449
|
] }),
|
|
3446
|
-
children: items.length === 0 ? /* @__PURE__ */ (0,
|
|
3450
|
+
children: items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Empty, { children: "Nothing to back up yet." }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Windowed, { items, render: (i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PickLine, { title: i.name, detail: i.definitionLabel, checked: selected.has(i.id), disabled: busy, onChange: (on) => pick(i.id, on) }, i.id) })
|
|
3447
3451
|
}
|
|
3448
3452
|
),
|
|
3449
|
-
backup ? /* @__PURE__ */ (0,
|
|
3450
|
-
/* @__PURE__ */ (0,
|
|
3451
|
-
/* @__PURE__ */ (0,
|
|
3452
|
-
/* @__PURE__ */ (0,
|
|
3453
|
-
/* @__PURE__ */ (0,
|
|
3454
|
-
/* @__PURE__ */ (0,
|
|
3453
|
+
backup ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3454
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Summary, { value: backup }),
|
|
3455
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3456
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { children: [
|
|
3457
|
+
/* @__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) }) }),
|
|
3458
|
+
/* @__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) }) })
|
|
3455
3459
|
] })
|
|
3456
3460
|
] }) : null
|
|
3457
|
-
] }) : /* @__PURE__ */ (0,
|
|
3458
|
-
/* @__PURE__ */ (0,
|
|
3459
|
-
/* @__PURE__ */ (0,
|
|
3460
|
-
/* @__PURE__ */ (0,
|
|
3461
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: !restorePreview ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { children: [
|
|
3462
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultRow, { label: "File", ...file ? { hint: file.name } : {}, children: [
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Button, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
|
|
3464
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3461
3465
|
"input",
|
|
3462
3466
|
{
|
|
3463
3467
|
ref: fileInput,
|
|
@@ -3471,16 +3475,16 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3471
3475
|
}
|
|
3472
3476
|
)
|
|
3473
3477
|
] }),
|
|
3474
|
-
/* @__PURE__ */ (0,
|
|
3475
|
-
] }) : /* @__PURE__ */ (0,
|
|
3476
|
-
/* @__PURE__ */ (0,
|
|
3477
|
-
!result ? /* @__PURE__ */ (0,
|
|
3478
|
-
!result ? /* @__PURE__ */ (0,
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Passphrase", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Field, { type: "password", value: passphrase, autoComplete: "current-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) })
|
|
3479
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3480
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Summary, { value: restorePreview }),
|
|
3481
|
+
!result ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
|
|
3482
|
+
!result ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "px-1 text-xs text-muted-foreground", children: "Restored items start disabled and restricted." }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultSection, { title: `${result.created} restored \xB7 ${result.replayed} already \xB7 ${result.refused} refused \xB7 ${result.retryable_failure} to retry`, children: result.results.map((r) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: names.get(r.source_item_id) ?? "Credential", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: r.status === "refused" || r.status === "retryable_failure" ? "text-destructive" : "text-foreground", children: [
|
|
3479
3483
|
RECORD_STATUS[r.status],
|
|
3480
3484
|
r.reason === "alias_conflict" ? " \xB7 name in use" : ""
|
|
3481
3485
|
] }) }, r.source_item_id)) })
|
|
3482
3486
|
] }) }),
|
|
3483
|
-
/* @__PURE__ */ (0,
|
|
3487
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ErrorLine, { message: error })
|
|
3484
3488
|
] });
|
|
3485
3489
|
}
|
|
3486
3490
|
|
|
@@ -3489,7 +3493,7 @@ var import_react19 = require("react");
|
|
|
3489
3493
|
var import_controls14 = require("@ai-matrx/design-system/controls");
|
|
3490
3494
|
var import_download2 = require("@ai-matrx/kit/download");
|
|
3491
3495
|
var import_confirm_opener5 = require("@ai-matrx/kit/confirm-opener");
|
|
3492
|
-
var
|
|
3496
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3493
3497
|
var FORMATS = [
|
|
3494
3498
|
{ value: "matrx_login_csv_v1", label: "Matrx", hint: "Website logins, all common fields" },
|
|
3495
3499
|
{ value: "firefox_csv_v1", label: "Firefox", hint: "Address, username and password" },
|
|
@@ -3563,24 +3567,24 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3563
3567
|
setBusy(false);
|
|
3564
3568
|
}
|
|
3565
3569
|
};
|
|
3566
|
-
return /* @__PURE__ */ (0,
|
|
3570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
3567
3571
|
Panel,
|
|
3568
3572
|
{
|
|
3569
3573
|
title: "Export logins",
|
|
3570
3574
|
size: "lg",
|
|
3571
3575
|
onClose,
|
|
3572
|
-
footer: /* @__PURE__ */ (0,
|
|
3573
|
-
/* @__PURE__ */ (0,
|
|
3574
|
-
preview ? /* @__PURE__ */ (0,
|
|
3576
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
3577
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_controls14.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3578
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_controls14.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
|
|
3575
3579
|
"Download ",
|
|
3576
3580
|
eligible
|
|
3577
|
-
] }) : /* @__PURE__ */ (0,
|
|
3581
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_controls14.Button, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void review(), children: [
|
|
3578
3582
|
"Review ",
|
|
3579
3583
|
selected.size
|
|
3580
3584
|
] })
|
|
3581
3585
|
] }),
|
|
3582
3586
|
children: [
|
|
3583
|
-
/* @__PURE__ */ (0,
|
|
3587
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VaultRow, { label: "Format", hint: format?.hint, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3584
3588
|
import_controls14.Select,
|
|
3585
3589
|
{
|
|
3586
3590
|
value: profile,
|
|
@@ -3592,21 +3596,21 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3592
3596
|
}
|
|
3593
3597
|
}
|
|
3594
3598
|
) }) }),
|
|
3595
|
-
/* @__PURE__ */ (0,
|
|
3599
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3596
3600
|
VaultSection,
|
|
3597
3601
|
{
|
|
3598
3602
|
title: `${selected.size} of ${plural(logins.length, "login")}`,
|
|
3599
|
-
actions: /* @__PURE__ */ (0,
|
|
3600
|
-
/* @__PURE__ */ (0,
|
|
3603
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
3604
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_controls14.Button, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
|
|
3601
3605
|
changed();
|
|
3602
3606
|
setSelected(new Set(logins.map((l) => l.id)));
|
|
3603
3607
|
}, children: "All" }),
|
|
3604
|
-
/* @__PURE__ */ (0,
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_controls14.Button, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
|
|
3605
3609
|
changed();
|
|
3606
3610
|
setSelected(/* @__PURE__ */ new Set());
|
|
3607
3611
|
}, children: "None" })
|
|
3608
3612
|
] }),
|
|
3609
|
-
children: logins.length === 0 ? /* @__PURE__ */ (0,
|
|
3613
|
+
children: logins.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Empty, { children: "No website logins to export." }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3610
3614
|
Windowed,
|
|
3611
3615
|
{
|
|
3612
3616
|
items: logins,
|
|
@@ -3614,7 +3618,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3614
3618
|
const p = reasons.get(item.id);
|
|
3615
3619
|
const left = p && !p.eligible;
|
|
3616
3620
|
const omitted = p ? omissionText2(p.omissions) : "";
|
|
3617
|
-
return /* @__PURE__ */ (0,
|
|
3621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3618
3622
|
PickLine,
|
|
3619
3623
|
{
|
|
3620
3624
|
title: item.name,
|
|
@@ -3632,7 +3636,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3632
3636
|
)
|
|
3633
3637
|
}
|
|
3634
3638
|
),
|
|
3635
|
-
/* @__PURE__ */ (0,
|
|
3639
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorLine, { message: error })
|
|
3636
3640
|
]
|
|
3637
3641
|
}
|
|
3638
3642
|
);
|
|
@@ -4150,7 +4154,7 @@ var import_zip2 = require("@zip.js/zip.js");
|
|
|
4150
4154
|
var safe = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
4151
4155
|
var unsafeName = (name) => /[\\\0-\x1F\x7F-\x9F]/.test(name);
|
|
4152
4156
|
function stopIfCancelled(signal) {
|
|
4153
|
-
if (signal?.aborted) throw new Error("The archive import was
|
|
4157
|
+
if (signal?.aborted) throw new Error("The archive import was canceled.");
|
|
4154
4158
|
}
|
|
4155
4159
|
function hasWarnings(reader, entry) {
|
|
4156
4160
|
return Boolean(reader.warnings?.length || entry.warnings?.length);
|
|
@@ -4251,7 +4255,7 @@ async function openBoundedZip(file, limits, signal) {
|
|
|
4251
4255
|
};
|
|
4252
4256
|
} catch (error) {
|
|
4253
4257
|
await reader.close();
|
|
4254
|
-
if (signal?.aborted) throw new Error("The archive import was
|
|
4258
|
+
if (signal?.aborted) throw new Error("The archive import was canceled.");
|
|
4255
4259
|
throw error;
|
|
4256
4260
|
}
|
|
4257
4261
|
}
|
|
@@ -4290,7 +4294,7 @@ async function readDashlaneCsvArchive(file, limits, signal) {
|
|
|
4290
4294
|
return { credentialsText, omittedCsvCount };
|
|
4291
4295
|
} catch (error) {
|
|
4292
4296
|
credentialsText = void 0;
|
|
4293
|
-
if (signal?.aborted) throw new Error("The Dashlane import was
|
|
4297
|
+
if (signal?.aborted) throw new Error("The Dashlane import was canceled.");
|
|
4294
4298
|
throw error;
|
|
4295
4299
|
} finally {
|
|
4296
4300
|
credentialsText = void 0;
|
|
@@ -4425,7 +4429,7 @@ function hasValidStructuredImportFileNotices(value, maxCount) {
|
|
|
4425
4429
|
}
|
|
4426
4430
|
|
|
4427
4431
|
// src/io/parse-source.ts
|
|
4428
|
-
var cancelled = () => new Error("The import was
|
|
4432
|
+
var cancelled = () => new Error("The import was canceled.");
|
|
4429
4433
|
function parseStructured(source, file, limits, signal) {
|
|
4430
4434
|
const descriptor = structuredImportSource(source);
|
|
4431
4435
|
if (!descriptor) return Promise.reject(new Error("This kind of file cannot be imported."));
|
|
@@ -4478,7 +4482,7 @@ async function parseImportFile(source, file, limits, signal) {
|
|
|
4478
4482
|
}
|
|
4479
4483
|
|
|
4480
4484
|
// src/io/ImportPanel.tsx
|
|
4481
|
-
var
|
|
4485
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
4482
4486
|
var ROLE_OPTIONS = [
|
|
4483
4487
|
{ value: "keep", label: "Keep encrypted" },
|
|
4484
4488
|
{ value: "title", label: "Name" },
|
|
@@ -4653,26 +4657,26 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4653
4657
|
const help = EXPORT_HELP[source];
|
|
4654
4658
|
const stage = done ? "done" : draft ? "review" : "choose";
|
|
4655
4659
|
const busy = running !== null || reading;
|
|
4656
|
-
const footer = stage === "choose" ? /* @__PURE__ */ (0,
|
|
4657
|
-
/* @__PURE__ */ (0,
|
|
4658
|
-
source === "env" ? /* @__PURE__ */ (0,
|
|
4659
|
-
] }) : stage === "review" ? /* @__PURE__ */ (0,
|
|
4660
|
-
running ? /* @__PURE__ */ (0,
|
|
4661
|
-
/* @__PURE__ */ (0,
|
|
4662
|
-
] }) : /* @__PURE__ */ (0,
|
|
4663
|
-
done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */ (0,
|
|
4664
|
-
/* @__PURE__ */ (0,
|
|
4660
|
+
const footer = stage === "choose" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
4661
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
4662
|
+
source === "env" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
|
|
4663
|
+
] }) : stage === "review" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
4664
|
+
running ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "quiet", onClick: reset, children: "Back" }),
|
|
4665
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImportGlyph, { className: "size-4" }), disabled: busy || chosen === 0 || ambiguous === true || needsApproval, onClick: start, children: running ? `Importing ${running.done} of ${running.total}` : `Import ${chosen}` })
|
|
4666
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
4667
|
+
done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "outline", disabled: busy, onClick: retry, children: running ? `Importing ${running.done} of ${running.total}` : `Try ${done.failed.length + done.untried.length} again` }) : null,
|
|
4668
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "primary", onClick: onClose, children: "Done" })
|
|
4665
4669
|
] });
|
|
4666
|
-
return /* @__PURE__ */ (0,
|
|
4667
|
-
stage === "choose" ? /* @__PURE__ */ (0,
|
|
4668
|
-
/* @__PURE__ */ (0,
|
|
4670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Panel, { title: "Import", size: "xl", onClose, footer, children: [
|
|
4671
|
+
stage === "choose" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(VaultSection, { children: [
|
|
4672
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Source", actions: help && host.openUrl ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "quiet", onClick: () => host.openUrl?.(help), children: "How to export" }) : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Select, { value: source, options: SOURCE_OPTIONS, "aria-label": "Source", onValueChange: (s) => {
|
|
4669
4673
|
setSource(s);
|
|
4670
4674
|
setError(null);
|
|
4671
4675
|
} }) }),
|
|
4672
|
-
source === "env" ? /* @__PURE__ */ (0,
|
|
4673
|
-
/* @__PURE__ */ (0,
|
|
4674
|
-
/* @__PURE__ */ (0,
|
|
4675
|
-
/* @__PURE__ */ (0,
|
|
4676
|
+
source === "env" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: ".env text", hint: "Same key updates in place", top: true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Textarea, { mono: true, rows: 7, value: envText, autoComplete: "off", spellCheck: false, "aria-label": ".env text", placeholder: "OPENAI_API_KEY=sk-...\nDATABASE_URL=postgres://...", onChange: (e) => setEnvText(e.target.value) }) }) : null,
|
|
4677
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(VaultRow, { label: "File", hint: fileName ?? void 0, children: [
|
|
4678
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "outline", disabled: reading, onClick: () => fileInput.current?.click(), children: reading ? "Reading\u2026" : source === "env" ? "Load a file" : "Choose a file" }),
|
|
4679
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4676
4680
|
"input",
|
|
4677
4681
|
{
|
|
4678
4682
|
ref: fileInput,
|
|
@@ -4687,44 +4691,44 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4687
4691
|
}
|
|
4688
4692
|
)
|
|
4689
4693
|
] }),
|
|
4690
|
-
source === "env" ? /* @__PURE__ */ (0,
|
|
4694
|
+
source === "env" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Sandboxes", hint: "Pass these values to agent sandboxes", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Switch, { checked: injectSandbox, onCheckedChange: setInjectSandbox, "aria-label": "Use in sandboxes" }) }) : null
|
|
4691
4695
|
] }) : null,
|
|
4692
|
-
stage === "review" && draft ? /* @__PURE__ */ (0,
|
|
4693
|
-
organizations.length > 0 ? /* @__PURE__ */ (0,
|
|
4694
|
-
/* @__PURE__ */ (0,
|
|
4696
|
+
stage === "review" && draft ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
4697
|
+
organizations.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Save to", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Select, { value: destination, options: destinationOptions, "aria-label": "Save to", onValueChange: (v) => draft.kind === "file" ? restart({ destination: v }) : setDestination(v) }) }) }) : null,
|
|
4698
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4695
4699
|
VaultSection,
|
|
4696
4700
|
{
|
|
4697
4701
|
title: draft.kind === "env" ? plural(envKeys.length, "value") : summary(counts, lines.length),
|
|
4698
|
-
actions: /* @__PURE__ */ (0,
|
|
4699
|
-
/* @__PURE__ */ (0,
|
|
4700
|
-
/* @__PURE__ */ (0,
|
|
4702
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
4703
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "quiet", disabled: busy, onClick: () => setSelected(draft.kind === "env" ? new Set(envKeys.map((e) => e.key + e.text)) : defaultSelection(lines)), children: "Reset" }),
|
|
4704
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Button, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
|
|
4701
4705
|
] }),
|
|
4702
|
-
children: draft.kind === "env" ? /* @__PURE__ */ (0,
|
|
4706
|
+
children: draft.kind === "env" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4703
4707
|
Windowed,
|
|
4704
4708
|
{
|
|
4705
4709
|
items: envKeys,
|
|
4706
4710
|
render: (e) => {
|
|
4707
4711
|
const id = e.key + e.text;
|
|
4708
|
-
return /* @__PURE__ */ (0,
|
|
4712
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLine, { title: e.key, detail: "Value hidden", checked: selected.has(id), disabled: busy, onChange: (on) => toggle(setSelected, id, on) }, id);
|
|
4709
4713
|
}
|
|
4710
4714
|
}
|
|
4711
|
-
) : lines.length === 0 ? /* @__PURE__ */ (0,
|
|
4715
|
+
) : lines.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Empty, { children: "Nothing to import in this file." }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4712
4716
|
Windowed,
|
|
4713
4717
|
{
|
|
4714
4718
|
items: lines,
|
|
4715
4719
|
render: (l) => {
|
|
4716
4720
|
const badge = STATE_BADGE[l.state];
|
|
4717
|
-
return /* @__PURE__ */ (0,
|
|
4721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLine, { title: l.title, detail: l.reason ?? l.detail, checked: selected.has(l.key), disabled: busy || !selectable(l), badge: badge?.text, tone: badge?.tone, onChange: (on) => toggle(setSelected, l.key, on) }, l.key);
|
|
4718
4722
|
}
|
|
4719
4723
|
}
|
|
4720
4724
|
)
|
|
4721
4725
|
}
|
|
4722
4726
|
),
|
|
4723
|
-
draft.kind === "file" && draft.parsed.kind === "structured" ? /* @__PURE__ */ (0,
|
|
4724
|
-
draft.kind === "file" ? /* @__PURE__ */ (0,
|
|
4725
|
-
draft.kind === "file" ? /* @__PURE__ */ (0,
|
|
4726
|
-
/* @__PURE__ */ (0,
|
|
4727
|
-
draft.parsed.kind === "csv" ? draft.parsed.preview.headers.map((header, index) => /* @__PURE__ */ (0,
|
|
4727
|
+
draft.kind === "file" && draft.parsed.kind === "structured" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Visible details", hint: "Approve saving websites and public keys in the clear", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Switch, { checked: approvedVisible, disabled: busy, onCheckedChange: setApprovedVisible, "aria-label": "Approve visible details" }) }) }) : null,
|
|
4728
|
+
draft.kind === "file" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notices, { draft }) : null,
|
|
4729
|
+
draft.kind === "file" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(More, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(VaultSection, { children: [
|
|
4730
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Browser fill", hint: "Needs username, password and an https address", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_controls15.Switch, { checked: browserFill, disabled: busy, onCheckedChange: (on) => restart({ browserFill: on }), "aria-label": "Browser fill" }) }),
|
|
4731
|
+
draft.parsed.kind === "csv" ? draft.parsed.preview.headers.map((header, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: header || `Column ${index + 1}`, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4728
4732
|
import_controls15.Select,
|
|
4729
4733
|
{
|
|
4730
4734
|
value: draft.mapping[index] ?? "keep",
|
|
@@ -4734,20 +4738,20 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4734
4738
|
}
|
|
4735
4739
|
) }, `${header}-${index}`)) : null
|
|
4736
4740
|
] }) }) : null,
|
|
4737
|
-
ambiguous ? /* @__PURE__ */ (0,
|
|
4741
|
+
ambiguous ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ErrorLine, { message: "Each of name, username, password, notes and one-time password can be used by one column." }) : null
|
|
4738
4742
|
] }) : null,
|
|
4739
|
-
stage === "done" && done ? /* @__PURE__ */ (0,
|
|
4740
|
-
/* @__PURE__ */ (0,
|
|
4741
|
-
/* @__PURE__ */ (0,
|
|
4742
|
-
/* @__PURE__ */ (0,
|
|
4743
|
-
done.untried.length > 0 ? /* @__PURE__ */ (0,
|
|
4744
|
-
done.withOtp > 0 ? /* @__PURE__ */ (0,
|
|
4743
|
+
stage === "done" && done ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(VaultSection, { title: "Result", children: [
|
|
4744
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Created", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-foreground", children: done.created.length }) }),
|
|
4745
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Skipped", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-foreground", children: done.skipped }) }),
|
|
4746
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Failed", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: done.failed.length > 0 ? "text-destructive" : "text-foreground", children: done.failed.length }) }),
|
|
4747
|
+
done.untried.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Not tried", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-foreground", children: done.untried.length }) }) : null,
|
|
4748
|
+
done.withOtp > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: "Codes", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
4745
4749
|
plural(done.withOtp, "login"),
|
|
4746
4750
|
" still need the one-time password added."
|
|
4747
4751
|
] }) }) : null,
|
|
4748
|
-
done.failed.map((f) => /* @__PURE__ */ (0,
|
|
4752
|
+
done.failed.map((f) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VaultRow, { label: f.title, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "block truncate text-destructive", title: f.reason, children: f.reason }) }, f.key))
|
|
4749
4753
|
] }) : null,
|
|
4750
|
-
/* @__PURE__ */ (0,
|
|
4754
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ErrorLine, { message: error })
|
|
4751
4755
|
] });
|
|
4752
4756
|
}
|
|
4753
4757
|
function toggle(set, key, on) {
|
|
@@ -4774,7 +4778,7 @@ function Notices({ draft }) {
|
|
|
4774
4778
|
}
|
|
4775
4779
|
}
|
|
4776
4780
|
if (notes.length === 0) return null;
|
|
4777
|
-
return /* @__PURE__ */ (0,
|
|
4781
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-col gap-0.5 px-1 text-xs text-muted-foreground", children: notes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: n }, n)) });
|
|
4778
4782
|
}
|
|
4779
4783
|
|
|
4780
4784
|
// src/ItemList.tsx
|
|
@@ -4783,20 +4787,6 @@ var import_design_system18 = require("@ai-matrx/design-system");
|
|
|
4783
4787
|
var import_design_system19 = require("@ai-matrx/design-system");
|
|
4784
4788
|
var import_controls22 = require("@ai-matrx/design-system/controls");
|
|
4785
4789
|
|
|
4786
|
-
// src/ItemIcon.tsx
|
|
4787
|
-
var import_design_system12 = require("@ai-matrx/design-system");
|
|
4788
|
-
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
4789
|
-
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
4790
|
-
const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
|
|
4791
|
-
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
4792
|
-
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
4793
|
-
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
4794
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: (0, import_design_system12.cn)("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
4795
|
-
}
|
|
4796
|
-
const Glyph = definitionGlyph(definitionKey, family);
|
|
4797
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: (0, import_design_system12.cn)("flex shrink-0 items-center justify-center", box, tone), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Glyph, { className: size === "lg" ? "size-5" : "size-4" }) });
|
|
4798
|
-
}
|
|
4799
|
-
|
|
4800
4790
|
// src/ItemPane.tsx
|
|
4801
4791
|
var import_react27 = require("react");
|
|
4802
4792
|
var import_design_system16 = require("@ai-matrx/design-system");
|
|
@@ -5719,6 +5709,8 @@ function ItemPane(props) {
|
|
|
5719
5709
|
const [tagsText, setTagsText] = (0, import_react27.useState)(base.tags.join(", "));
|
|
5720
5710
|
const [showTags, setShowTags] = (0, import_react27.useState)(false);
|
|
5721
5711
|
const [showDescription, setShowDescription] = (0, import_react27.useState)(false);
|
|
5712
|
+
const [showRecovery, setShowRecovery] = (0, import_react27.useState)(false);
|
|
5713
|
+
const [settingUpOtp, setSettingUpOtp] = (0, import_react27.useState)(false);
|
|
5722
5714
|
const [owner, setOwner] = (0, import_react27.useState)(defaultOwner ?? "me");
|
|
5723
5715
|
const [recipient, setRecipient] = (0, import_react27.useState)("");
|
|
5724
5716
|
const [generatePrivately, setGeneratePrivately] = (0, import_react27.useState)(false);
|
|
@@ -5747,6 +5739,7 @@ function ItemPane(props) {
|
|
|
5747
5739
|
setLoaded({});
|
|
5748
5740
|
setShowTags(false);
|
|
5749
5741
|
setShowDescription(false);
|
|
5742
|
+
setShowRecovery(false);
|
|
5750
5743
|
}, [item?.id, mode]);
|
|
5751
5744
|
(0, import_react27.useEffect)(() => onDirty(dirty), [dirty, onDirty]);
|
|
5752
5745
|
const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
|
|
@@ -5774,23 +5767,24 @@ function ItemPane(props) {
|
|
|
5774
5767
|
setBusy(true);
|
|
5775
5768
|
setError(null);
|
|
5776
5769
|
const out = { ...draft, values: Object.fromEntries(changedValues(base, draft)) };
|
|
5770
|
+
if (out.values[RECOVERY_CODES_KEY] !== void 0) out.values[RECOVERY_CODES_KEY] = parseRecoveryCodes(out.values[RECOVERY_CODES_KEY]).join("\n");
|
|
5777
5771
|
const withOtp = async (saved, notice2) => {
|
|
5778
5772
|
const setup = out.authenticator.trim();
|
|
5779
|
-
if (!setup) return [saved, notice2];
|
|
5773
|
+
if (!setup) return [saved, notice2, false];
|
|
5780
5774
|
try {
|
|
5781
5775
|
await confirmed(() => port.authenticator.enrol(saved, setup));
|
|
5782
|
-
return [await port.get(saved), notice2];
|
|
5776
|
+
return [await port.get(saved), notice2, true];
|
|
5783
5777
|
} catch (e) {
|
|
5784
5778
|
const why = wasCancelled(e) ? "it was not confirmed" : e instanceof Error ? e.message : "it was refused";
|
|
5785
|
-
return [saved, `Saved, but the
|
|
5779
|
+
return [saved, `Saved, but the authenticator was not set up: ${why}. Add it with Edit.`, false];
|
|
5786
5780
|
}
|
|
5787
5781
|
};
|
|
5788
5782
|
try {
|
|
5789
5783
|
if (item) {
|
|
5790
5784
|
const r = await port.save(item, definition, out);
|
|
5791
|
-
const [next, n] = await withOtp(r.item, r.notice);
|
|
5785
|
+
const [next, n, enrolled] = await withOtp(r.item, r.notice);
|
|
5792
5786
|
(0, import_drafts.dropKeptDraft)(keepKey);
|
|
5793
|
-
onSaved(next, false, n);
|
|
5787
|
+
onSaved(next, false, n, enrolled);
|
|
5794
5788
|
} else if (definition && owner === "person") {
|
|
5795
5789
|
const secretKey = declared.find((f) => f.storage === "encrypted" && f.kind === "secret")?.key ?? null;
|
|
5796
5790
|
const r = await port.sharing.assign({ recipientEmail: recipient.trim(), definition, draft: out, generateFieldKey: generatePrivately ? secretKey : null });
|
|
@@ -5798,9 +5792,9 @@ function ItemPane(props) {
|
|
|
5798
5792
|
onCancelNew();
|
|
5799
5793
|
} else if (definition) {
|
|
5800
5794
|
const r = await port.create(definition, owner === "me" ? null : owner, out);
|
|
5801
|
-
const [next, n] = await withOtp(r.item, r.notice);
|
|
5795
|
+
const [next, n, enrolled] = await withOtp(r.item, r.notice);
|
|
5802
5796
|
(0, import_drafts.dropKeptDraft)(keepKey);
|
|
5803
|
-
onSaved(next, true, n);
|
|
5797
|
+
onSaved(next, true, n, enrolled);
|
|
5804
5798
|
}
|
|
5805
5799
|
} catch (e) {
|
|
5806
5800
|
setError(e instanceof Error ? e.message : "Saving failed. Nothing was changed.");
|
|
@@ -5859,6 +5853,10 @@ function ItemPane(props) {
|
|
|
5859
5853
|
const viewCustom = (item?.custom ?? []).filter((c) => !declaredKeys.has(c.key) && c.key !== MFA_METHOD_KEY && !isAuthenticatorStorage(c.key));
|
|
5860
5854
|
const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
|
|
5861
5855
|
const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
|
|
5856
|
+
const recoveryDeclared = declaredKeys.has(RECOVERY_CODES_KEY);
|
|
5857
|
+
const recoveryExtra = extraFields.some(isRecoveryCodesField);
|
|
5858
|
+
const offerRecovery = isLogin || Boolean(item?.authenticator) || draft.authenticator.trim() !== "";
|
|
5859
|
+
const recoveryEditing = !recoveryDeclared && !recoveryExtra && (showRecovery || (draft.values[RECOVERY_CODES_KEY] ?? "") !== "");
|
|
5862
5860
|
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BuildingGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_icons11.UsersIcon, {}) } : null;
|
|
5863
5861
|
const sameNamed = (id) => {
|
|
5864
5862
|
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
@@ -6006,7 +6004,8 @@ function ItemPane(props) {
|
|
|
6006
6004
|
label: f.label,
|
|
6007
6005
|
value: draft.values[f.key] ?? "",
|
|
6008
6006
|
placeholder: f.handling === "visible" || f.key in loaded ? "" : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
6009
|
-
secret: f.handling !== "visible",
|
|
6007
|
+
secret: f.handling !== "visible" && !isRecoveryCodesField(f),
|
|
6008
|
+
multiline: isRecoveryCodesField(f),
|
|
6010
6009
|
onChange: (v) => setValue(f.key, v),
|
|
6011
6010
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
6012
6011
|
removeLabel: `Delete ${f.label}`,
|
|
@@ -6043,7 +6042,27 @@ function ItemPane(props) {
|
|
|
6043
6042
|
)),
|
|
6044
6043
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
6045
6044
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
6046
|
-
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
6045
|
+
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null,
|
|
6046
|
+
recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
6047
|
+
EditRow,
|
|
6048
|
+
{
|
|
6049
|
+
label: "Recovery codes",
|
|
6050
|
+
value: draft.values[RECOVERY_CODES_KEY] ?? "",
|
|
6051
|
+
multiline: true,
|
|
6052
|
+
autoFocus: showRecovery && (draft.values[RECOVERY_CODES_KEY] ?? "") === "",
|
|
6053
|
+
placeholder: "Backup codes, one per line",
|
|
6054
|
+
onChange: (v) => setValue(RECOVERY_CODES_KEY, v),
|
|
6055
|
+
onRemove: () => {
|
|
6056
|
+
setShowRecovery(false);
|
|
6057
|
+
setDraft((d) => {
|
|
6058
|
+
const values = { ...d.values };
|
|
6059
|
+
delete values[RECOVERY_CODES_KEY];
|
|
6060
|
+
return { ...d, values };
|
|
6061
|
+
});
|
|
6062
|
+
},
|
|
6063
|
+
removeLabel: "Remove recovery codes"
|
|
6064
|
+
}
|
|
6065
|
+
) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "Recovery codes", onAdd: () => setShowRecovery(true), children: "Add backup codes" }) : null
|
|
6047
6066
|
] }),
|
|
6048
6067
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
|
|
6049
6068
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
@@ -6056,7 +6075,8 @@ function ItemPane(props) {
|
|
|
6056
6075
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_design_system16.DropdownMenuItem, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
|
|
6057
6076
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_design_system16.DropdownMenuItem, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
|
|
6058
6077
|
!tagsVisible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_design_system16.DropdownMenuItem, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
|
|
6059
|
-
!descriptionVisible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_design_system16.DropdownMenuItem, { onSelect: () => setShowDescription(true), children: "Description" }) : null
|
|
6078
|
+
!descriptionVisible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_design_system16.DropdownMenuItem, { onSelect: () => setShowDescription(true), children: "Description" }) : null,
|
|
6079
|
+
!recoveryDeclared && !recoveryExtra && !recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_design_system16.DropdownMenuItem, { onSelect: () => setShowRecovery(true), children: "Recovery codes" }) : null
|
|
6060
6080
|
] })
|
|
6061
6081
|
] }),
|
|
6062
6082
|
children: [
|
|
@@ -6096,8 +6116,9 @@ function ItemPane(props) {
|
|
|
6096
6116
|
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
|
|
6097
6117
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6098
6118
|
// which would invite replacing a working two-factor secret.
|
|
6099
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultRow, { label: "
|
|
6100
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "
|
|
6119
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
6120
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "Authenticator", onAdd: canEdit ? () => setSettingUpOtp(true) : null, children: "Set up" }),
|
|
6121
|
+
!recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RecoveryCodesRow, { item, field: null, port, onChanged }) : null,
|
|
6101
6122
|
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
6102
6123
|
] }),
|
|
6103
6124
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { children: item.notes ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
|
|
@@ -6113,7 +6134,22 @@ function ItemPane(props) {
|
|
|
6113
6134
|
" \xB7 Created ",
|
|
6114
6135
|
(0, import_format8.formatAbsoluteDate)(item.createdAt, DAY_FORMAT, "")
|
|
6115
6136
|
] })
|
|
6116
|
-
] }) : null }) })
|
|
6137
|
+
] }) : null }) }),
|
|
6138
|
+
settingUpOtp && item ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
6139
|
+
AddOtpPanel,
|
|
6140
|
+
{
|
|
6141
|
+
port,
|
|
6142
|
+
items: [item],
|
|
6143
|
+
definitions: definition ? [definition] : [],
|
|
6144
|
+
itemId: item.id,
|
|
6145
|
+
onClose: () => setSettingUpOtp(false),
|
|
6146
|
+
onChanged: () => onChanged(),
|
|
6147
|
+
onDone: () => {
|
|
6148
|
+
setSettingUpOtp(false);
|
|
6149
|
+
onChanged();
|
|
6150
|
+
}
|
|
6151
|
+
}
|
|
6152
|
+
) : null
|
|
6117
6153
|
] }) });
|
|
6118
6154
|
}
|
|
6119
6155
|
|
|
@@ -7051,7 +7087,7 @@ var plural2 = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
|
7051
7087
|
function terminalMessage(s) {
|
|
7052
7088
|
if (s.phase === "completed") return `Imported ${plural2(s.committed, "passkey")}.`;
|
|
7053
7089
|
if (s.phase === "partial") return `${s.committed} imported; ${s.unsupported + s.failed + s.uncertain + s.not_attempted} need attention.`;
|
|
7054
|
-
if (s.phase === "cancelled") return "Import
|
|
7090
|
+
if (s.phase === "cancelled") return "Import canceled. Nothing else will be imported.";
|
|
7055
7091
|
if (s.phase === "unavailable") return "Passkey import is unavailable here.";
|
|
7056
7092
|
if (s.phase === "failed") return "The import did not finish. Recover it before using a new file.";
|
|
7057
7093
|
return s.message;
|
|
@@ -7236,7 +7272,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7236
7272
|
present(g, { kind: "status", status: result, message: terminalMessage(result) });
|
|
7237
7273
|
if (!done && ACTIVE_PHASES.has(result.phase)) schedulePoll(active.id);
|
|
7238
7274
|
} catch (e) {
|
|
7239
|
-
keepOperation(g, fail(e, "The import could not be
|
|
7275
|
+
keepOperation(g, fail(e, "The import could not be canceled."));
|
|
7240
7276
|
} finally {
|
|
7241
7277
|
if (current(g)) setBusy(false);
|
|
7242
7278
|
}
|
|
@@ -7722,6 +7758,7 @@ var import_design_system24 = require("@ai-matrx/design-system");
|
|
|
7722
7758
|
var import_controls33 = require("@ai-matrx/design-system/controls");
|
|
7723
7759
|
var import_icons15 = require("@ai-matrx/design-system/icons");
|
|
7724
7760
|
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
7761
|
+
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
7725
7762
|
function vaultChoices(items, organizations, current) {
|
|
7726
7763
|
const n = (f) => items.filter(f).length;
|
|
7727
7764
|
const shared = n((i) => i.owner.kind === "shared");
|
|
@@ -7761,7 +7798,7 @@ function buildViews(items, definitions, favoriteIds2, recentIds2) {
|
|
|
7761
7798
|
function viewLabel(view, views) {
|
|
7762
7799
|
if (view === "favorites") return "Favorites";
|
|
7763
7800
|
if (view === "recent") return "Recently opened";
|
|
7764
|
-
if (view === "authenticator") return
|
|
7801
|
+
if (view === "authenticator") return AUTHENTICATOR_LABEL;
|
|
7765
7802
|
if (view === "trash") return "Trash";
|
|
7766
7803
|
if (view === "page") return "This page";
|
|
7767
7804
|
return [...views.categories, ...views.tags].find((v) => v.view === view)?.label ?? "All items";
|
|
@@ -7772,7 +7809,7 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
|
|
|
7772
7809
|
{ value: "all", label: "Every category", meta: String(allCount) },
|
|
7773
7810
|
...hasFavorites ? [{ value: "favorites", label: "Favorites", meta: views.favorites === void 0 ? "" : String(views.favorites) }] : [],
|
|
7774
7811
|
...hasRecents ? [{ value: "recent", label: "Recently opened", meta: views.recent === void 0 ? "" : String(views.recent) }] : [],
|
|
7775
|
-
{ value: "authenticator", label:
|
|
7812
|
+
{ value: "authenticator", label: AUTHENTICATOR_LABEL, meta: String(views.authenticator) },
|
|
7776
7813
|
...views.categories.map((v) => ({ value: v.view, label: v.label, meta: String(v.count) })),
|
|
7777
7814
|
...views.tags.map((v) => ({ value: v.view, label: `#${v.label}`, meta: String(v.count) })),
|
|
7778
7815
|
{ value: "trash", label: "Trash", meta: String(deletedCount) }
|
|
@@ -7814,7 +7851,7 @@ function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, v
|
|
|
7814
7851
|
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Entry, { on: view === "all", glyph: GridGlyph, label: "All items", count: allCount, onClick: () => onView("all") }),
|
|
7815
7852
|
hasFavorites ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Entry, { on: view === "favorites", glyph: StarGlyph, label: "Favorites", count: views.favorites, onClick: () => onView("favorites") }) : null,
|
|
7816
7853
|
hasRecents ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Entry, { on: view === "recent", glyph: ClockGlyph, label: "Recently opened", count: views.recent, onClick: () => onView("recent") }) : null,
|
|
7817
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Entry, { on: view === "authenticator", glyph: LockGlyph, label:
|
|
7854
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Entry, { on: view === "authenticator", glyph: LockGlyph, label: AUTHENTICATOR_LABEL, count: views.authenticator, onClick: () => onView("authenticator") })
|
|
7818
7855
|
] }),
|
|
7819
7856
|
views.categories.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Group, { title: "Categories", children: views.categories.map((e) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) }) : null,
|
|
7820
7857
|
views.tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
@@ -7921,6 +7958,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7921
7958
|
const loc = location ?? inner;
|
|
7922
7959
|
const dirty = (0, import_react41.useRef)(false);
|
|
7923
7960
|
const [notice, setNotice] = (0, import_react41.useState)(null);
|
|
7961
|
+
const [firstCode, setFirstCode] = (0, import_react41.useState)(null);
|
|
7924
7962
|
const move = (0, import_react41.useCallback)(
|
|
7925
7963
|
(next, how) => {
|
|
7926
7964
|
if (!location) setInner(next);
|
|
@@ -8060,9 +8098,21 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8060
8098
|
}
|
|
8061
8099
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8062
8100
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8063
|
-
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)
|
|
8101
|
+
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto] gap-2", children: [
|
|
8064
8102
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
|
|
8065
8103
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Select, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" }),
|
|
8104
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
8105
|
+
import_controls34.Button,
|
|
8106
|
+
{
|
|
8107
|
+
variant: loc.view === "authenticator" ? "outline" : "quiet",
|
|
8108
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LockGlyph, {}),
|
|
8109
|
+
"aria-label": AUTHENTICATOR_LABEL,
|
|
8110
|
+
"aria-pressed": loc.view === "authenticator",
|
|
8111
|
+
title: AUTHENTICATOR_LABEL,
|
|
8112
|
+
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null }),
|
|
8113
|
+
children: mode === "split" ? AUTHENTICATOR_LABEL : null
|
|
8114
|
+
}
|
|
8115
|
+
),
|
|
8066
8116
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_design_system25.DropdownMenu, { children: [
|
|
8067
8117
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system25.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8068
8118
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_design_system25.DropdownMenuContent, { align: "end", children: [
|
|
@@ -8163,9 +8213,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8163
8213
|
seed: { name: guess?.name ?? "", url: guess?.url ?? loc.url.trim() },
|
|
8164
8214
|
onBack: () => go({ kind: null }),
|
|
8165
8215
|
onMode: () => void 0,
|
|
8166
|
-
onSaved: (item, _wasNew, n) => {
|
|
8216
|
+
onSaved: (item, _wasNew, n, enrolled) => {
|
|
8167
8217
|
replaceItem(item);
|
|
8168
8218
|
dirty.current = false;
|
|
8219
|
+
if (enrolled) setFirstCode(item);
|
|
8169
8220
|
move({ ...loc, itemId: item.id, mode: "view", kind: null, url: "", panel: null }, "replace");
|
|
8170
8221
|
setNotice(n);
|
|
8171
8222
|
notify("Saved");
|
|
@@ -8194,9 +8245,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8194
8245
|
onBack: back,
|
|
8195
8246
|
onMode: (m) => go({ mode: m, panel: null }),
|
|
8196
8247
|
notice,
|
|
8197
|
-
onSaved: (item, _wasNew, n) => {
|
|
8248
|
+
onSaved: (item, _wasNew, n, enrolled) => {
|
|
8198
8249
|
replaceItem(item);
|
|
8199
8250
|
dirty.current = false;
|
|
8251
|
+
if (enrolled) setFirstCode(item);
|
|
8200
8252
|
move({ ...loc, mode: "view" }, "replace");
|
|
8201
8253
|
setNotice(n);
|
|
8202
8254
|
notify("Saved");
|
|
@@ -8294,7 +8346,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8294
8346
|
) : null,
|
|
8295
8347
|
shown.list ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
|
|
8296
8348
|
shown.detail ? detail : null,
|
|
8297
|
-
panel
|
|
8349
|
+
panel,
|
|
8350
|
+
firstCode ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FirstCodePanel, { port, item: firstCode, onClose: () => setFirstCode(null), onDone: () => setFirstCode(null) }) : null
|
|
8298
8351
|
] })
|
|
8299
8352
|
] });
|
|
8300
8353
|
}
|
|
@@ -9065,7 +9118,9 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9065
9118
|
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 }))],
|
|
9066
9119
|
fields: [
|
|
9067
9120
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
9068
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map((s) => ({ field_key: fieldKeyOf(s.label), value: s.value, handling: "revealable" }))
|
|
9121
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map((s) => ({ field_key: fieldKeyOf(s.label), value: s.value, handling: "revealable" })),
|
|
9122
|
+
// Backup codes on a type that does not declare them (a website login): their own encrypted field.
|
|
9123
|
+
...!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" }] : []
|
|
9069
9124
|
]
|
|
9070
9125
|
}
|
|
9071
9126
|
}, organizationId ? { organizationId } : void 0);
|