@ai-matrx/vault 0.1.54 → 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 +5 -4
- package/dist/index.cjs +69 -16
- 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 +70 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
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
|
+
|
|
3
7
|
## 0.1.54
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/vault`.
|
|
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.
|
|
7
10
|
|
|
8
11
|
## 0.1.53
|
|
9
12
|
|
|
@@ -359,8 +362,6 @@ Changed shipped source files (8):
|
|
|
359
362
|
## 0.1.7
|
|
360
363
|
### Unreleased
|
|
361
364
|
|
|
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
365
|
- Host-held lock: `host.lock` (`VaultLock`: `locked`, `subscribe`, `unlock`, optional `lock` and
|
|
365
366
|
`unlockLabel`). While locked the vault shows only "Vault locked" with Unlock, and every port call
|
|
366
367
|
(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 }),
|
|
@@ -9687,6 +9716,30 @@ var import_account = require("@ai-matrx/api/account");
|
|
|
9687
9716
|
var import_architecture = require("@ai-matrx/api/architecture");
|
|
9688
9717
|
function createHealthPort(api) {
|
|
9689
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
|
+
},
|
|
9690
9743
|
start: (requestId, signal, options) => (0, import_account.startPasswordHealthScan)(api, { body: options.check_breaches ? { check_breaches: true } : {} }, { requestId, signal, totalTimeoutMs: null }),
|
|
9691
9744
|
resume: (executionId, requestId, signal) => (0, import_account.resumePasswordHealthScan)(api, { path: { execution_id: executionId } }, { requestId, signal, totalTimeoutMs: null }),
|
|
9692
9745
|
read: (executionId, signal) => (0, import_account.getPasswordHealthScan)(api, { path: { execution_id: executionId } }, { signal }),
|