@ai-matrx/vault 0.1.54 → 0.1.56
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 +9 -4
- package/dist/index.cjs +120 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +121 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.56
|
|
4
|
+
|
|
5
|
+
- No changes yet.
|
|
6
|
+
|
|
7
|
+
## 0.1.55
|
|
8
|
+
|
|
9
|
+
- Password Health can discover a prior scan when neither request nor execution handle is available, and binds recovered results and progress to the originating health port. Consumer action: custom `HealthPort` implementations must provide `discover(cursor, signal)`; `createApiVaultPort` wires it automatically. Discovery returns authorized request/execution references only. External request/execution handle changes retire pending work and recover the new address; matching self-written handles preserve the current run.
|
|
10
|
+
|
|
3
11
|
## 0.1.54
|
|
4
12
|
|
|
5
|
-
|
|
6
|
-
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/vault`.
|
|
13
|
+
- Saved health recovery shows Checking status while its read is pending. A missing execution or failed initial recovery read settles as Unavailable and keeps Retry available. Consumer action: none; the existing request/execution handle round trip is unchanged.
|
|
7
14
|
|
|
8
15
|
## 0.1.53
|
|
9
16
|
|
|
@@ -359,8 +366,6 @@ Changed shipped source files (8):
|
|
|
359
366
|
## 0.1.7
|
|
360
367
|
### Unreleased
|
|
361
368
|
|
|
362
|
-
- Saved health recovery shows Checking status while its read is pending. A missing execution or failed initial recovery read settles as Unavailable and keeps Retry available. Consumer action: none; the existing request/execution handle round trip is unchanged.
|
|
363
|
-
|
|
364
369
|
- Host-held lock: `host.lock` (`VaultLock`: `locked`, `subscribe`, `unlock`, optional `lock` and
|
|
365
370
|
`unlockLabel`). While locked the vault shows only "Vault locked" with Unlock, and every port call
|
|
366
371
|
(areas included) is refused at call time (`guardPort`, `VaultLockedError`). "Lock" joins the
|
package/dist/index.cjs
CHANGED
|
@@ -682,7 +682,7 @@ function PasswordHealthView(props) {
|
|
|
682
682
|
const latest = (0, import_react4.useRef)(props);
|
|
683
683
|
latest.current = props;
|
|
684
684
|
const [result, setResult] = (0, import_react4.useState)(null);
|
|
685
|
-
const [status, setStatus] = (0, import_react4.useState)(
|
|
685
|
+
const [status, setStatus] = (0, import_react4.useState)("Checking status");
|
|
686
686
|
const [error, setError] = (0, import_react4.useState)(null);
|
|
687
687
|
const [progress, setProgress] = (0, import_react4.useState)(null);
|
|
688
688
|
const [busy, setBusy] = (0, import_react4.useState)(false);
|
|
@@ -692,9 +692,13 @@ function PasswordHealthView(props) {
|
|
|
692
692
|
}, [port]);
|
|
693
693
|
const [retry, setRetry] = (0, import_react4.useState)(0);
|
|
694
694
|
const active = (0, import_react4.useRef)(null);
|
|
695
|
-
const starting = (0, import_react4.useRef)(
|
|
695
|
+
const starting = (0, import_react4.useRef)(null);
|
|
696
696
|
const ownedAddress = (0, import_react4.useRef)(null);
|
|
697
697
|
const writeReference = (request, execution) => {
|
|
698
|
+
if (starting.current?.controller === active.current) {
|
|
699
|
+
starting.current.request = request;
|
|
700
|
+
starting.current.execution = execution;
|
|
701
|
+
}
|
|
698
702
|
ownedAddress.current = { request, execution, items: latest.current.items, retry };
|
|
699
703
|
latest.current.onReference(request, execution);
|
|
700
704
|
};
|
|
@@ -722,7 +726,7 @@ function PasswordHealthView(props) {
|
|
|
722
726
|
const value = await port.read(id, controller.signal);
|
|
723
727
|
if (owns(controller)) {
|
|
724
728
|
setStatus(STATUS_LABEL[value.execution_status]);
|
|
725
|
-
setResult({ value, items: inventory });
|
|
729
|
+
setResult({ value, items: inventory, port });
|
|
726
730
|
}
|
|
727
731
|
return value;
|
|
728
732
|
};
|
|
@@ -740,6 +744,27 @@ function PasswordHealthView(props) {
|
|
|
740
744
|
}
|
|
741
745
|
writeReference(request, id);
|
|
742
746
|
}
|
|
747
|
+
if (!id && !request) {
|
|
748
|
+
let cursor;
|
|
749
|
+
const seen = /* @__PURE__ */ new Set();
|
|
750
|
+
do {
|
|
751
|
+
const page = await port.discover(cursor, controller.signal);
|
|
752
|
+
if (!owns(controller)) return;
|
|
753
|
+
const reference = page.references[0];
|
|
754
|
+
if (reference) {
|
|
755
|
+
id = reference.execution_id;
|
|
756
|
+
writeReference(reference.request_id, reference.execution_id);
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
cursor = page.continuation ?? void 0;
|
|
760
|
+
if (cursor && seen.has(cursor)) throw new Error("Report unavailable");
|
|
761
|
+
if (cursor) seen.add(cursor);
|
|
762
|
+
} while (cursor);
|
|
763
|
+
if (!id) {
|
|
764
|
+
setStatus("No report");
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
743
768
|
if (!id || !owns(controller)) return;
|
|
744
769
|
const first = await read(id, controller);
|
|
745
770
|
if (!owns(controller) || terminal(first.execution_status)) return;
|
|
@@ -749,7 +774,7 @@ function PasswordHealthView(props) {
|
|
|
749
774
|
if (!owns(controller)) return;
|
|
750
775
|
const detail = event.detail;
|
|
751
776
|
if (event.kind === "note" && detail?.label === "password_health_progress" && detail.__kind === "password_health_progress" && typeof detail.checked === "number" && Number.isSafeInteger(detail.checked) && detail.checked >= 0 && typeof detail.skipped === "number" && Number.isSafeInteger(detail.skipped) && detail.skipped >= 0) {
|
|
752
|
-
setProgress({ checked: detail.checked, skipped: detail.skipped });
|
|
777
|
+
setProgress({ checked: detail.checked, skipped: detail.skipped, port });
|
|
753
778
|
}
|
|
754
779
|
const lifecycle = event.kind === "started" || event.kind === "resumed" ? "running" : event.kind === "created" ? "pending" : event.kind;
|
|
755
780
|
const label = STATUS_LABEL[lifecycle];
|
|
@@ -764,14 +789,16 @@ function PasswordHealthView(props) {
|
|
|
764
789
|
if (!inventoryReady) {
|
|
765
790
|
ownedAddress.current = null;
|
|
766
791
|
setResult(null);
|
|
767
|
-
if (!starting.current) active.current?.abort();
|
|
792
|
+
if (!starting.current || !owns(starting.current.controller)) active.current?.abort();
|
|
768
793
|
return;
|
|
769
794
|
}
|
|
770
|
-
if (!port
|
|
795
|
+
if (!port) return;
|
|
796
|
+
const start = starting.current;
|
|
797
|
+
if (start && owns(start.controller) && start.request === (requestId ?? "") && start.execution === (executionId ?? "")) return;
|
|
771
798
|
const own = ownedAddress.current;
|
|
772
799
|
if (own && own.request === requestId && own.execution === executionId && own.items === items && own.retry === retry && active.current && !active.current.signal.aborted) return;
|
|
773
800
|
const controller = fresh();
|
|
774
|
-
setStatus(
|
|
801
|
+
setStatus("Checking status");
|
|
775
802
|
void recover(requestId, executionId, controller).catch((e) => {
|
|
776
803
|
if (owns(controller)) {
|
|
777
804
|
setResult(null);
|
|
@@ -793,7 +820,7 @@ function PasswordHealthView(props) {
|
|
|
793
820
|
const run = async (resume2) => {
|
|
794
821
|
if (!port) return;
|
|
795
822
|
const controller = fresh();
|
|
796
|
-
starting.current =
|
|
823
|
+
starting.current = { controller, request: "", execution: "" };
|
|
797
824
|
const request = crypto.randomUUID();
|
|
798
825
|
const options = { check_breaches: checkBreaches };
|
|
799
826
|
let actualRequest = request;
|
|
@@ -822,7 +849,7 @@ function PasswordHealthView(props) {
|
|
|
822
849
|
if (data && typeof data === "object" && "type" in data) {
|
|
823
850
|
if (data.type === "vault_password_health_scan_reference") accept(data);
|
|
824
851
|
if (data.type === "vault_password_health_progress") {
|
|
825
|
-
setProgress(data);
|
|
852
|
+
setProgress({ ...data, port });
|
|
826
853
|
setStatus("Running");
|
|
827
854
|
}
|
|
828
855
|
}
|
|
@@ -866,20 +893,22 @@ function PasswordHealthView(props) {
|
|
|
866
893
|
setError(problem(e));
|
|
867
894
|
setStatus((value) => value === "Checking status" ? "Unavailable" : value);
|
|
868
895
|
} finally {
|
|
869
|
-
starting.current =
|
|
896
|
+
if (starting.current?.controller === controller) starting.current = null;
|
|
870
897
|
if (owns(controller)) {
|
|
871
898
|
setBusy(false);
|
|
872
899
|
if (startedItems !== latest.current.items) setRetry((v) => v + 1);
|
|
873
900
|
}
|
|
874
901
|
}
|
|
875
902
|
};
|
|
876
|
-
const
|
|
877
|
-
const
|
|
903
|
+
const ownedResult = port && result?.port === port ? result : null;
|
|
904
|
+
const shownProgress = port && progress?.port === port ? progress : null;
|
|
905
|
+
const current = inventoryReady && ownedResult?.items === items && ownedResult.value.availability === "current" ? ownedResult.value.snapshot : null;
|
|
906
|
+
const available = ownedResult?.value.availability;
|
|
878
907
|
const outcomes = current?.check_breaches ? current.breach_outcomes ?? [] : [];
|
|
879
908
|
const compromised = outcomes.filter((outcome) => outcome.status === "compromised").length;
|
|
880
909
|
const notFound = outcomes.filter((outcome) => outcome.status === "not_found").length;
|
|
881
910
|
const unknown = outcomes.filter((outcome) => outcome.status === "unknown").length;
|
|
882
|
-
const resume =
|
|
911
|
+
const resume = ownedResult && ["failed", "cancelled"].includes(ownedResult.value.execution_status);
|
|
883
912
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex h-full min-h-0 flex-col gap-4 overflow-auto p-4", "aria-label": "Password health", children: [
|
|
884
913
|
props.header,
|
|
885
914
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
@@ -913,9 +942,9 @@ function PasswordHealthView(props) {
|
|
|
913
942
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.InfoHint, { text: "The breach lookup could not establish a result." })
|
|
914
943
|
] }), children: unknown })
|
|
915
944
|
] }) : null,
|
|
916
|
-
!current &&
|
|
917
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Checked", children:
|
|
918
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Skipped", children:
|
|
945
|
+
!current && shownProgress ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
946
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Checked", children: shownProgress.checked }),
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Skipped", children: shownProgress.skipped })
|
|
919
948
|
] }) : null,
|
|
920
949
|
current ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
921
950
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Checked", children: current.checked_subjects.length }),
|
|
@@ -2673,7 +2702,7 @@ function normalizeWebsite(raw) {
|
|
|
2673
2702
|
}
|
|
2674
2703
|
function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onAdded, onDone }) {
|
|
2675
2704
|
const confirmed = useConfirmed();
|
|
2676
|
-
const candidates = items.filter((i) => !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
|
|
2705
|
+
const candidates = items.filter((i) => i.authenticatorState === "known" && !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
|
|
2677
2706
|
const [input, setInput] = (0, import_react13.useState)("");
|
|
2678
2707
|
const [image, setImage] = (0, import_react13.useState)(null);
|
|
2679
2708
|
const [target, setTarget] = (0, import_react13.useState)(itemId && candidates.some((c) => c.id === itemId) ? itemId : NEW);
|
|
@@ -2712,7 +2741,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2712
2741
|
}
|
|
2713
2742
|
const it = item;
|
|
2714
2743
|
const entry = await confirmed(() => image ? port.authenticator.enrolQrImage(it, image, image.name) : port.authenticator.enrol(it, input));
|
|
2715
|
-
let next = { ...it, authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
|
|
2744
|
+
let next = { ...it, authenticatorState: "known", authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
|
|
2716
2745
|
const better = authenticatorName(it.name, { issuer: entry.issuer, account: entry.account });
|
|
2717
2746
|
if (!isNew && better !== it.name) {
|
|
2718
2747
|
try {
|
|
@@ -2850,6 +2879,7 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2850
2879
|
(0, import_react14.useEffect)(() => {
|
|
2851
2880
|
if (added.size > 0 && [...added.keys()].every((id) => listed.some((i) => i.id === id && i.authenticator))) setAdded(/* @__PURE__ */ new Map());
|
|
2852
2881
|
}, [listed, added]);
|
|
2882
|
+
const [incomplete, setIncomplete] = (0, import_react14.useState)(true);
|
|
2853
2883
|
const [entries, setEntries] = (0, import_react14.useState)(/* @__PURE__ */ new Map());
|
|
2854
2884
|
const [hidden, setHidden] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
2855
2885
|
const [adding, setAdding] = (0, import_react14.useState)(false);
|
|
@@ -2859,8 +2889,15 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2859
2889
|
(0, import_react14.useEffect)(() => {
|
|
2860
2890
|
let live = true;
|
|
2861
2891
|
port.authenticator.list().then(
|
|
2862
|
-
(list) =>
|
|
2863
|
-
|
|
2892
|
+
(list) => {
|
|
2893
|
+
if (live) {
|
|
2894
|
+
setEntries(new Map(list.entries.map((e) => [e.itemId, e])));
|
|
2895
|
+
setIncomplete(list.unavailableScopes.length > 0);
|
|
2896
|
+
}
|
|
2897
|
+
},
|
|
2898
|
+
() => {
|
|
2899
|
+
if (live) setIncomplete(true);
|
|
2900
|
+
}
|
|
2864
2901
|
);
|
|
2865
2902
|
return () => {
|
|
2866
2903
|
live = false;
|
|
@@ -2878,7 +2915,14 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2878
2915
|
] }),
|
|
2879
2916
|
total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
|
|
2880
2917
|
] }),
|
|
2881
|
-
total
|
|
2918
|
+
total > 0 && incomplete ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-4 text-sm text-muted-foreground", children: [
|
|
2919
|
+
"Some codes unavailable ",
|
|
2920
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
|
|
2921
|
+
] }) : null,
|
|
2922
|
+
total === 0 && (incomplete || items.some((i) => i.authenticatorState !== "known")) ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: [
|
|
2923
|
+
"Codes unavailable ",
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
|
|
2925
|
+
] }) : total === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
|
|
2882
2926
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ShieldGlyph, { className: "size-6" }) }),
|
|
2883
2927
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
|
|
2884
2928
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
|
|
@@ -6925,7 +6969,10 @@ function ItemPane(props) {
|
|
|
6925
6969
|
i
|
|
6926
6970
|
)),
|
|
6927
6971
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
6928
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
6972
|
+
!item || item.authenticatorState === "known" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(VaultRow, { label: "Authenticator", children: [
|
|
6973
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
|
|
6974
|
+
item.authenticatorState === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
|
|
6975
|
+
] }),
|
|
6929
6976
|
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null,
|
|
6930
6977
|
!item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
|
|
6931
6978
|
recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
@@ -7004,7 +7051,10 @@ function ItemPane(props) {
|
|
|
7004
7051
|
}),
|
|
7005
7052
|
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
|
|
7006
7053
|
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
7007
|
-
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpRow, { port, item, onChanged }) :
|
|
7054
|
+
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpRow, { port, item, onChanged }) : item.authenticatorState !== "known" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(VaultRow, { label: "Authenticator", children: [
|
|
7055
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
|
|
7056
|
+
item.authenticatorState === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
|
|
7057
|
+
] }) : seedField && !seedField.active ? (
|
|
7008
7058
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
7009
7059
|
// which would invite replacing a working two-factor secret.
|
|
7010
7060
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
@@ -9687,6 +9737,30 @@ var import_account = require("@ai-matrx/api/account");
|
|
|
9687
9737
|
var import_architecture = require("@ai-matrx/api/architecture");
|
|
9688
9738
|
function createHealthPort(api) {
|
|
9689
9739
|
return {
|
|
9740
|
+
discover: async (cursor, signal) => {
|
|
9741
|
+
const stream = await (0, import_account.discoverPasswordHealthScans)(api, cursor ? { query: { cursor } } : void 0, { signal, totalTimeoutMs: null });
|
|
9742
|
+
let page = null;
|
|
9743
|
+
let ended = false;
|
|
9744
|
+
try {
|
|
9745
|
+
for await (const event of stream) {
|
|
9746
|
+
if (signal.aborted || ended || event.event === "error") throw new Error("Report unavailable");
|
|
9747
|
+
const data = event.data;
|
|
9748
|
+
if (event.event === "completion" && data && typeof data === "object" && "status" in data && data.status !== "success") throw new Error("Report unavailable");
|
|
9749
|
+
if (event.event === "end") {
|
|
9750
|
+
if (!data || typeof data !== "object" || !("reason" in data) || data.reason !== "complete") throw new Error("Report unavailable");
|
|
9751
|
+
ended = true;
|
|
9752
|
+
}
|
|
9753
|
+
if (event.event !== "data") continue;
|
|
9754
|
+
if (!data || typeof data !== "object" || !("type" in data) || data.type !== "vault_password_health_discovery_page") continue;
|
|
9755
|
+
if (page || !("__kind" in data) || data.__kind !== "password_health_discovery_page" || !("references" in data) || !Array.isArray(data.references) || data.references.some((ref) => !ref || typeof ref !== "object" || ref.__kind !== "password_health_discovery_reference" || typeof ref.request_id !== "string" || !ref.request_id || typeof ref.execution_id !== "string" || !ref.execution_id) || !("continuation" in data) || data.continuation !== null && (typeof data.continuation !== "string" || !data.continuation)) throw new Error("Report unavailable");
|
|
9756
|
+
page = data;
|
|
9757
|
+
}
|
|
9758
|
+
if (signal.aborted || !ended || !page) throw new Error("Report unavailable");
|
|
9759
|
+
return page;
|
|
9760
|
+
} finally {
|
|
9761
|
+
stream.cancel();
|
|
9762
|
+
}
|
|
9763
|
+
},
|
|
9690
9764
|
start: (requestId, signal, options) => (0, import_account.startPasswordHealthScan)(api, { body: options.check_breaches ? { check_breaches: true } : {} }, { requestId, signal, totalTimeoutMs: null }),
|
|
9691
9765
|
resume: (executionId, requestId, signal) => (0, import_account.resumePasswordHealthScan)(api, { path: { execution_id: executionId } }, { requestId, signal, totalTimeoutMs: null }),
|
|
9692
9766
|
read: (executionId, signal) => (0, import_account.getPasswordHealthScan)(api, { path: { execution_id: executionId } }, { signal }),
|
|
@@ -9809,7 +9883,7 @@ function createAuthenticatorPort(ctx) {
|
|
|
9809
9883
|
return {
|
|
9810
9884
|
async list() {
|
|
9811
9885
|
const r = await apps.listAuthenticators(api);
|
|
9812
|
-
return (r.entries ?? []).map(entryOf);
|
|
9886
|
+
return { entries: (r.entries ?? []).map(entryOf), unavailableScopes: (r.unavailable_scopes ?? []).map((s) => ({ type: s.type, organizationId: s.organization_id ?? null })) };
|
|
9813
9887
|
},
|
|
9814
9888
|
async get(item) {
|
|
9815
9889
|
try {
|
|
@@ -10023,6 +10097,7 @@ function trashItem(r, ctx) {
|
|
|
10023
10097
|
fields: [],
|
|
10024
10098
|
custom: [],
|
|
10025
10099
|
authenticator: null,
|
|
10100
|
+
authenticatorState: "known",
|
|
10026
10101
|
capabilities: { canUse: false, canEdit: false, canReveal: false, canManage: true },
|
|
10027
10102
|
attachments: [],
|
|
10028
10103
|
uriMatchMode: "host",
|
|
@@ -10379,7 +10454,8 @@ function fieldOf(w, def) {
|
|
|
10379
10454
|
active: w.is_active ?? true
|
|
10380
10455
|
};
|
|
10381
10456
|
}
|
|
10382
|
-
|
|
10457
|
+
var scopeUnavailable = (owner, scopes) => scopes.some((s) => s.type === (owner.kind === "me" ? "user" : owner.kind === "organization" ? "organization" : "shared") && (s.type !== "organization" || !s.organization_id || s.organization_id === owner.organizationId));
|
|
10458
|
+
function itemOf(w, owner, defs, auth, state = "known", unavailable = [], inventoryOwner = owner) {
|
|
10383
10459
|
const def = defs.get(w.definition_key ?? "");
|
|
10384
10460
|
const a = auth.get(w.id);
|
|
10385
10461
|
const cap = w.capabilities ?? {};
|
|
@@ -10397,6 +10473,7 @@ function itemOf(w, owner, defs, auth) {
|
|
|
10397
10473
|
fields: (w.fields ?? []).filter((f) => f.execution_purpose !== "passkey_private").map((f) => fieldOf(f, def)),
|
|
10398
10474
|
custom: (w.non_secret_fields ?? []).map((c) => ({ key: c["key"] ?? "", label: c["label"] ?? humanize(c["key"] ?? ""), value: c["value"] ?? "" })),
|
|
10399
10475
|
authenticator: a ? { digits: a.digits, period: a.period, enabled: a.enabled } : null,
|
|
10476
|
+
authenticatorState: a ? "known" : state === "pending" ? "pending" : state === "unavailable" || scopeUnavailable(inventoryOwner, unavailable) ? "unavailable" : "known",
|
|
10400
10477
|
capabilities: { canUse: cap.can_use ?? false, canEdit: cap.can_edit ?? false, canReveal: cap.can_reveal ?? false, canManage: cap.can_manage ?? false },
|
|
10401
10478
|
attachments: (w.attachments ?? []).map((a2) => ({ id: a2.id, label: a2.label, description: a2.description ?? "", fileName: a2.file_name, mediaType: a2.media_type ?? "application/octet-stream", sizeBytes: a2.size_bytes, handling: handlingOf(a2.handling), createdAt: a2.created_at, updatedAt: a2.updated_at })),
|
|
10402
10479
|
uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
|
|
@@ -10433,6 +10510,9 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10433
10510
|
};
|
|
10434
10511
|
let defs = /* @__PURE__ */ new Map();
|
|
10435
10512
|
let auth = /* @__PURE__ */ new Map();
|
|
10513
|
+
let authState = "pending";
|
|
10514
|
+
let authUnavailable = [];
|
|
10515
|
+
let inventoryOwners = /* @__PURE__ */ new Map();
|
|
10436
10516
|
let orgs = [];
|
|
10437
10517
|
const orgOf = (id, userId, mine) => {
|
|
10438
10518
|
if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
|
|
@@ -10446,7 +10526,7 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10446
10526
|
};
|
|
10447
10527
|
async function refetch(id, owner) {
|
|
10448
10528
|
const w = await account9.getItem(api, { path: { item_id: id } });
|
|
10449
|
-
return itemOf(w, owner, defs, auth);
|
|
10529
|
+
return itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwners.get(id) ?? owner);
|
|
10450
10530
|
}
|
|
10451
10531
|
const visibleCache = /* @__PURE__ */ new Map();
|
|
10452
10532
|
const ctx = {
|
|
@@ -10473,6 +10553,10 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10473
10553
|
fields: createFieldsPort(ctx),
|
|
10474
10554
|
lists: createListsPort(ctx, options.userState),
|
|
10475
10555
|
async load(onProgress) {
|
|
10556
|
+
authState = "pending";
|
|
10557
|
+
auth = /* @__PURE__ */ new Map();
|
|
10558
|
+
authUnavailable = [];
|
|
10559
|
+
inventoryOwners = /* @__PURE__ */ new Map();
|
|
10476
10560
|
const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
|
|
10477
10561
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
10478
10562
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
@@ -10495,9 +10579,10 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10495
10579
|
const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
|
|
10496
10580
|
const seen = /* @__PURE__ */ new Map();
|
|
10497
10581
|
const deleted = /* @__PURE__ */ new Map();
|
|
10498
|
-
const take = (w, owner) => {
|
|
10582
|
+
const take = (w, owner, inventoryOwner = owner) => {
|
|
10499
10583
|
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
|
|
10500
|
-
|
|
10584
|
+
inventoryOwners.set(w.id, inventoryOwner);
|
|
10585
|
+
const item = itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwner);
|
|
10501
10586
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
10502
10587
|
};
|
|
10503
10588
|
for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
|
|
@@ -10505,7 +10590,7 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10505
10590
|
const via = orgs[i];
|
|
10506
10591
|
for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
|
|
10507
10592
|
});
|
|
10508
|
-
for (const w of raw.shared?.items ?? []) take(w, w.organization_id ? orgOf(w.organization_id, null, false) : { kind: "shared", label: "Shared with me", organizationId: null });
|
|
10593
|
+
for (const w of raw.shared?.items ?? []) take(w, w.organization_id ? orgOf(w.organization_id, null, false) : { kind: "shared", label: "Shared with me", organizationId: null }, { kind: "shared", label: "Shared with me", organizationId: null });
|
|
10509
10594
|
const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
|
|
10510
10595
|
return {
|
|
10511
10596
|
unavailable: [...unavailable],
|
|
@@ -10564,9 +10649,14 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10564
10649
|
})();
|
|
10565
10650
|
quiet(orgListsReady);
|
|
10566
10651
|
const authDone = authP.then((a) => {
|
|
10567
|
-
|
|
10652
|
+
authUnavailable = a.unavailable_scopes ?? [];
|
|
10653
|
+
const fresh = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
|
|
10654
|
+
auth = fresh;
|
|
10655
|
+
authState = "known";
|
|
10656
|
+
if (authUnavailable.length) unavailable.push("One-time codes");
|
|
10568
10657
|
progress();
|
|
10569
10658
|
}, () => {
|
|
10659
|
+
authState = "unavailable";
|
|
10570
10660
|
unavailable.push("One-time codes");
|
|
10571
10661
|
});
|
|
10572
10662
|
const sharedDone = sharedP.then((sh) => {
|