@ai-matrx/vault 0.1.53 → 0.1.55
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 +8 -0
- package/dist/index.cjs +72 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +73 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.55
|
|
4
|
+
|
|
5
|
+
- 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.
|
|
6
|
+
|
|
7
|
+
## 0.1.54
|
|
8
|
+
|
|
9
|
+
- 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.
|
|
10
|
+
|
|
3
11
|
## 0.1.53
|
|
4
12
|
|
|
5
13
|
- Added the shared Password health view, durable scan recovery, explicit unchecked breach lookup, current-result accounting and existing editor remediation. Consumer action: adopt the compatible generated API with health stream types and runtime follower before this Vault package, and verify server support. Breach checks require explicit selection; unknown coverage remains visible. Installed and native acceptance remain separate.
|
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
|
};
|
|
@@ -734,11 +738,33 @@ function PasswordHealthView(props) {
|
|
|
734
738
|
if (!owns(controller)) return;
|
|
735
739
|
id = known.operations[0]?.execution_id;
|
|
736
740
|
if (!id) {
|
|
741
|
+
setStatus("Unavailable");
|
|
737
742
|
setError("Status unavailable");
|
|
738
743
|
return;
|
|
739
744
|
}
|
|
740
745
|
writeReference(request, id);
|
|
741
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
|
+
}
|
|
742
768
|
if (!id || !owns(controller)) return;
|
|
743
769
|
const first = await read(id, controller);
|
|
744
770
|
if (!owns(controller) || terminal(first.execution_status)) return;
|
|
@@ -748,7 +774,7 @@ function PasswordHealthView(props) {
|
|
|
748
774
|
if (!owns(controller)) return;
|
|
749
775
|
const detail = event.detail;
|
|
750
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) {
|
|
751
|
-
setProgress({ checked: detail.checked, skipped: detail.skipped });
|
|
777
|
+
setProgress({ checked: detail.checked, skipped: detail.skipped, port });
|
|
752
778
|
}
|
|
753
779
|
const lifecycle = event.kind === "started" || event.kind === "resumed" ? "running" : event.kind === "created" ? "pending" : event.kind;
|
|
754
780
|
const label = STATUS_LABEL[lifecycle];
|
|
@@ -763,17 +789,21 @@ function PasswordHealthView(props) {
|
|
|
763
789
|
if (!inventoryReady) {
|
|
764
790
|
ownedAddress.current = null;
|
|
765
791
|
setResult(null);
|
|
766
|
-
if (!starting.current) active.current?.abort();
|
|
792
|
+
if (!starting.current || !owns(starting.current.controller)) active.current?.abort();
|
|
767
793
|
return;
|
|
768
794
|
}
|
|
769
|
-
if (!port
|
|
795
|
+
if (!port) return;
|
|
796
|
+
const start = starting.current;
|
|
797
|
+
if (start && owns(start.controller) && start.request === (requestId ?? "") && start.execution === (executionId ?? "")) return;
|
|
770
798
|
const own = ownedAddress.current;
|
|
771
799
|
if (own && own.request === requestId && own.execution === executionId && own.items === items && own.retry === retry && active.current && !active.current.signal.aborted) return;
|
|
772
800
|
const controller = fresh();
|
|
801
|
+
setStatus("Checking status");
|
|
773
802
|
void recover(requestId, executionId, controller).catch((e) => {
|
|
774
803
|
if (owns(controller)) {
|
|
775
804
|
setResult(null);
|
|
776
805
|
setError(problem(e));
|
|
806
|
+
setStatus((value) => value === "Checking status" ? "Unavailable" : value);
|
|
777
807
|
}
|
|
778
808
|
}).finally(() => {
|
|
779
809
|
if (owns(controller)) setBusy(false);
|
|
@@ -790,7 +820,7 @@ function PasswordHealthView(props) {
|
|
|
790
820
|
const run = async (resume2) => {
|
|
791
821
|
if (!port) return;
|
|
792
822
|
const controller = fresh();
|
|
793
|
-
starting.current =
|
|
823
|
+
starting.current = { controller, request: "", execution: "" };
|
|
794
824
|
const request = crypto.randomUUID();
|
|
795
825
|
const options = { check_breaches: checkBreaches };
|
|
796
826
|
let actualRequest = request;
|
|
@@ -819,7 +849,7 @@ function PasswordHealthView(props) {
|
|
|
819
849
|
if (data && typeof data === "object" && "type" in data) {
|
|
820
850
|
if (data.type === "vault_password_health_scan_reference") accept(data);
|
|
821
851
|
if (data.type === "vault_password_health_progress") {
|
|
822
|
-
setProgress(data);
|
|
852
|
+
setProgress({ ...data, port });
|
|
823
853
|
setStatus("Running");
|
|
824
854
|
}
|
|
825
855
|
}
|
|
@@ -861,21 +891,24 @@ function PasswordHealthView(props) {
|
|
|
861
891
|
}
|
|
862
892
|
setResult(null);
|
|
863
893
|
setError(problem(e));
|
|
894
|
+
setStatus((value) => value === "Checking status" ? "Unavailable" : value);
|
|
864
895
|
} finally {
|
|
865
|
-
starting.current =
|
|
896
|
+
if (starting.current?.controller === controller) starting.current = null;
|
|
866
897
|
if (owns(controller)) {
|
|
867
898
|
setBusy(false);
|
|
868
899
|
if (startedItems !== latest.current.items) setRetry((v) => v + 1);
|
|
869
900
|
}
|
|
870
901
|
}
|
|
871
902
|
};
|
|
872
|
-
const
|
|
873
|
-
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;
|
|
874
907
|
const outcomes = current?.check_breaches ? current.breach_outcomes ?? [] : [];
|
|
875
908
|
const compromised = outcomes.filter((outcome) => outcome.status === "compromised").length;
|
|
876
909
|
const notFound = outcomes.filter((outcome) => outcome.status === "not_found").length;
|
|
877
910
|
const unknown = outcomes.filter((outcome) => outcome.status === "unknown").length;
|
|
878
|
-
const resume =
|
|
911
|
+
const resume = ownedResult && ["failed", "cancelled"].includes(ownedResult.value.execution_status);
|
|
879
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: [
|
|
880
913
|
props.header,
|
|
881
914
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
@@ -909,9 +942,9 @@ function PasswordHealthView(props) {
|
|
|
909
942
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.InfoHint, { text: "The breach lookup could not establish a result." })
|
|
910
943
|
] }), children: unknown })
|
|
911
944
|
] }) : null,
|
|
912
|
-
!current &&
|
|
913
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Checked", children:
|
|
914
|
-
/* @__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 })
|
|
915
948
|
] }) : null,
|
|
916
949
|
current ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
917
950
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label: "Checked", children: current.checked_subjects.length }),
|
|
@@ -9683,6 +9716,30 @@ var import_account = require("@ai-matrx/api/account");
|
|
|
9683
9716
|
var import_architecture = require("@ai-matrx/api/architecture");
|
|
9684
9717
|
function createHealthPort(api) {
|
|
9685
9718
|
return {
|
|
9719
|
+
discover: async (cursor, signal) => {
|
|
9720
|
+
const stream = await (0, import_account.discoverPasswordHealthScans)(api, cursor ? { query: { cursor } } : void 0, { signal, totalTimeoutMs: null });
|
|
9721
|
+
let page = null;
|
|
9722
|
+
let ended = false;
|
|
9723
|
+
try {
|
|
9724
|
+
for await (const event of stream) {
|
|
9725
|
+
if (signal.aborted || ended || event.event === "error") throw new Error("Report unavailable");
|
|
9726
|
+
const data = event.data;
|
|
9727
|
+
if (event.event === "completion" && data && typeof data === "object" && "status" in data && data.status !== "success") throw new Error("Report unavailable");
|
|
9728
|
+
if (event.event === "end") {
|
|
9729
|
+
if (!data || typeof data !== "object" || !("reason" in data) || data.reason !== "complete") throw new Error("Report unavailable");
|
|
9730
|
+
ended = true;
|
|
9731
|
+
}
|
|
9732
|
+
if (event.event !== "data") continue;
|
|
9733
|
+
if (!data || typeof data !== "object" || !("type" in data) || data.type !== "vault_password_health_discovery_page") continue;
|
|
9734
|
+
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");
|
|
9735
|
+
page = data;
|
|
9736
|
+
}
|
|
9737
|
+
if (signal.aborted || !ended || !page) throw new Error("Report unavailable");
|
|
9738
|
+
return page;
|
|
9739
|
+
} finally {
|
|
9740
|
+
stream.cancel();
|
|
9741
|
+
}
|
|
9742
|
+
},
|
|
9686
9743
|
start: (requestId, signal, options) => (0, import_account.startPasswordHealthScan)(api, { body: options.check_breaches ? { check_breaches: true } : {} }, { requestId, signal, totalTimeoutMs: null }),
|
|
9687
9744
|
resume: (executionId, requestId, signal) => (0, import_account.resumePasswordHealthScan)(api, { path: { execution_id: executionId } }, { requestId, signal, totalTimeoutMs: null }),
|
|
9688
9745
|
read: (executionId, signal) => (0, import_account.getPasswordHealthScan)(api, { path: { execution_id: executionId } }, { signal }),
|