@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/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ import { Look } from '@ai-matrx/design-system';
|
|
|
3
3
|
import { ApiStream, NdjsonEvent, JsonOrStream, FollowRuntimeOperationToEndOptions, FollowRuntimeOperationToEndResult, Api } from '@ai-matrx/api';
|
|
4
4
|
import * as account from '@ai-matrx/api/account';
|
|
5
5
|
import { VaultPasswordHealthScanRequest, VaultPasswordHealthScanReferenceData, PasswordHealthDurableResult } from '@ai-matrx/api/account';
|
|
6
|
+
import { VaultPasswordHealthDiscoveryPageData } from '@ai-matrx/api/stream';
|
|
6
7
|
import { OperationStatusResult } from '@ai-matrx/api/architecture';
|
|
7
8
|
import { VaultIdentity } from './identity.cjs';
|
|
8
9
|
export { CONFIRM_RETURN_KEY, Confirmed, IdentityAccount, IdentityGate, IdentityMethod, ReturnStore, SupabaseAuthLike, SupabaseIdentityOptions, createSupabaseIdentity, needsRecentSignIn, useConfirmed, wasCancelled } from './identity.cjs';
|
|
@@ -222,6 +223,7 @@ type HealthScanOptions = VaultPasswordHealthScanRequest;
|
|
|
222
223
|
type HealthResult = PasswordHealthDurableResult;
|
|
223
224
|
type HealthReference = VaultPasswordHealthScanReferenceData;
|
|
224
225
|
interface HealthPort {
|
|
226
|
+
discover(cursor: string | undefined, signal: AbortSignal): Promise<VaultPasswordHealthDiscoveryPageData>;
|
|
225
227
|
start(requestId: string, signal: AbortSignal, options: HealthScanOptions): Promise<ApiStream<NdjsonEvent>>;
|
|
226
228
|
resume(executionId: string, requestId: string, signal: AbortSignal): Promise<JsonOrStream<HealthReference, NdjsonEvent>>;
|
|
227
229
|
read(executionId: string, signal: AbortSignal): Promise<HealthResult>;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Look } from '@ai-matrx/design-system';
|
|
|
3
3
|
import { ApiStream, NdjsonEvent, JsonOrStream, FollowRuntimeOperationToEndOptions, FollowRuntimeOperationToEndResult, Api } from '@ai-matrx/api';
|
|
4
4
|
import * as account from '@ai-matrx/api/account';
|
|
5
5
|
import { VaultPasswordHealthScanRequest, VaultPasswordHealthScanReferenceData, PasswordHealthDurableResult } from '@ai-matrx/api/account';
|
|
6
|
+
import { VaultPasswordHealthDiscoveryPageData } from '@ai-matrx/api/stream';
|
|
6
7
|
import { OperationStatusResult } from '@ai-matrx/api/architecture';
|
|
7
8
|
import { VaultIdentity } from './identity.js';
|
|
8
9
|
export { CONFIRM_RETURN_KEY, Confirmed, IdentityAccount, IdentityGate, IdentityMethod, ReturnStore, SupabaseAuthLike, SupabaseIdentityOptions, createSupabaseIdentity, needsRecentSignIn, useConfirmed, wasCancelled } from './identity.js';
|
|
@@ -222,6 +223,7 @@ type HealthScanOptions = VaultPasswordHealthScanRequest;
|
|
|
222
223
|
type HealthResult = PasswordHealthDurableResult;
|
|
223
224
|
type HealthReference = VaultPasswordHealthScanReferenceData;
|
|
224
225
|
interface HealthPort {
|
|
226
|
+
discover(cursor: string | undefined, signal: AbortSignal): Promise<VaultPasswordHealthDiscoveryPageData>;
|
|
225
227
|
start(requestId: string, signal: AbortSignal, options: HealthScanOptions): Promise<ApiStream<NdjsonEvent>>;
|
|
226
228
|
resume(executionId: string, requestId: string, signal: AbortSignal): Promise<JsonOrStream<HealthReference, NdjsonEvent>>;
|
|
227
229
|
read(executionId: string, signal: AbortSignal): Promise<HealthResult>;
|
package/dist/index.js
CHANGED
|
@@ -146,7 +146,7 @@ function PasswordHealthView(props) {
|
|
|
146
146
|
const latest = useRef(props);
|
|
147
147
|
latest.current = props;
|
|
148
148
|
const [result, setResult] = useState2(null);
|
|
149
|
-
const [status, setStatus] = useState2("
|
|
149
|
+
const [status, setStatus] = useState2("Checking status");
|
|
150
150
|
const [error, setError] = useState2(null);
|
|
151
151
|
const [progress, setProgress] = useState2(null);
|
|
152
152
|
const [busy, setBusy] = useState2(false);
|
|
@@ -156,9 +156,13 @@ function PasswordHealthView(props) {
|
|
|
156
156
|
}, [port]);
|
|
157
157
|
const [retry, setRetry] = useState2(0);
|
|
158
158
|
const active = useRef(null);
|
|
159
|
-
const starting = useRef(
|
|
159
|
+
const starting = useRef(null);
|
|
160
160
|
const ownedAddress = useRef(null);
|
|
161
161
|
const writeReference = (request, execution) => {
|
|
162
|
+
if (starting.current?.controller === active.current) {
|
|
163
|
+
starting.current.request = request;
|
|
164
|
+
starting.current.execution = execution;
|
|
165
|
+
}
|
|
162
166
|
ownedAddress.current = { request, execution, items: latest.current.items, retry };
|
|
163
167
|
latest.current.onReference(request, execution);
|
|
164
168
|
};
|
|
@@ -186,7 +190,7 @@ function PasswordHealthView(props) {
|
|
|
186
190
|
const value = await port.read(id, controller.signal);
|
|
187
191
|
if (owns(controller)) {
|
|
188
192
|
setStatus(STATUS_LABEL[value.execution_status]);
|
|
189
|
-
setResult({ value, items: inventory });
|
|
193
|
+
setResult({ value, items: inventory, port });
|
|
190
194
|
}
|
|
191
195
|
return value;
|
|
192
196
|
};
|
|
@@ -198,11 +202,33 @@ function PasswordHealthView(props) {
|
|
|
198
202
|
if (!owns(controller)) return;
|
|
199
203
|
id = known.operations[0]?.execution_id;
|
|
200
204
|
if (!id) {
|
|
205
|
+
setStatus("Unavailable");
|
|
201
206
|
setError("Status unavailable");
|
|
202
207
|
return;
|
|
203
208
|
}
|
|
204
209
|
writeReference(request, id);
|
|
205
210
|
}
|
|
211
|
+
if (!id && !request) {
|
|
212
|
+
let cursor;
|
|
213
|
+
const seen = /* @__PURE__ */ new Set();
|
|
214
|
+
do {
|
|
215
|
+
const page = await port.discover(cursor, controller.signal);
|
|
216
|
+
if (!owns(controller)) return;
|
|
217
|
+
const reference = page.references[0];
|
|
218
|
+
if (reference) {
|
|
219
|
+
id = reference.execution_id;
|
|
220
|
+
writeReference(reference.request_id, reference.execution_id);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
cursor = page.continuation ?? void 0;
|
|
224
|
+
if (cursor && seen.has(cursor)) throw new Error("Report unavailable");
|
|
225
|
+
if (cursor) seen.add(cursor);
|
|
226
|
+
} while (cursor);
|
|
227
|
+
if (!id) {
|
|
228
|
+
setStatus("No report");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
206
232
|
if (!id || !owns(controller)) return;
|
|
207
233
|
const first = await read(id, controller);
|
|
208
234
|
if (!owns(controller) || terminal(first.execution_status)) return;
|
|
@@ -212,7 +238,7 @@ function PasswordHealthView(props) {
|
|
|
212
238
|
if (!owns(controller)) return;
|
|
213
239
|
const detail = event.detail;
|
|
214
240
|
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) {
|
|
215
|
-
setProgress({ checked: detail.checked, skipped: detail.skipped });
|
|
241
|
+
setProgress({ checked: detail.checked, skipped: detail.skipped, port });
|
|
216
242
|
}
|
|
217
243
|
const lifecycle = event.kind === "started" || event.kind === "resumed" ? "running" : event.kind === "created" ? "pending" : event.kind;
|
|
218
244
|
const label = STATUS_LABEL[lifecycle];
|
|
@@ -227,17 +253,21 @@ function PasswordHealthView(props) {
|
|
|
227
253
|
if (!inventoryReady) {
|
|
228
254
|
ownedAddress.current = null;
|
|
229
255
|
setResult(null);
|
|
230
|
-
if (!starting.current) active.current?.abort();
|
|
256
|
+
if (!starting.current || !owns(starting.current.controller)) active.current?.abort();
|
|
231
257
|
return;
|
|
232
258
|
}
|
|
233
|
-
if (!port
|
|
259
|
+
if (!port) return;
|
|
260
|
+
const start = starting.current;
|
|
261
|
+
if (start && owns(start.controller) && start.request === (requestId ?? "") && start.execution === (executionId ?? "")) return;
|
|
234
262
|
const own = ownedAddress.current;
|
|
235
263
|
if (own && own.request === requestId && own.execution === executionId && own.items === items && own.retry === retry && active.current && !active.current.signal.aborted) return;
|
|
236
264
|
const controller = fresh();
|
|
265
|
+
setStatus("Checking status");
|
|
237
266
|
void recover(requestId, executionId, controller).catch((e) => {
|
|
238
267
|
if (owns(controller)) {
|
|
239
268
|
setResult(null);
|
|
240
269
|
setError(problem(e));
|
|
270
|
+
setStatus((value) => value === "Checking status" ? "Unavailable" : value);
|
|
241
271
|
}
|
|
242
272
|
}).finally(() => {
|
|
243
273
|
if (owns(controller)) setBusy(false);
|
|
@@ -254,7 +284,7 @@ function PasswordHealthView(props) {
|
|
|
254
284
|
const run = async (resume2) => {
|
|
255
285
|
if (!port) return;
|
|
256
286
|
const controller = fresh();
|
|
257
|
-
starting.current =
|
|
287
|
+
starting.current = { controller, request: "", execution: "" };
|
|
258
288
|
const request = crypto.randomUUID();
|
|
259
289
|
const options = { check_breaches: checkBreaches };
|
|
260
290
|
let actualRequest = request;
|
|
@@ -283,7 +313,7 @@ function PasswordHealthView(props) {
|
|
|
283
313
|
if (data && typeof data === "object" && "type" in data) {
|
|
284
314
|
if (data.type === "vault_password_health_scan_reference") accept(data);
|
|
285
315
|
if (data.type === "vault_password_health_progress") {
|
|
286
|
-
setProgress(data);
|
|
316
|
+
setProgress({ ...data, port });
|
|
287
317
|
setStatus("Running");
|
|
288
318
|
}
|
|
289
319
|
}
|
|
@@ -325,21 +355,24 @@ function PasswordHealthView(props) {
|
|
|
325
355
|
}
|
|
326
356
|
setResult(null);
|
|
327
357
|
setError(problem(e));
|
|
358
|
+
setStatus((value) => value === "Checking status" ? "Unavailable" : value);
|
|
328
359
|
} finally {
|
|
329
|
-
starting.current =
|
|
360
|
+
if (starting.current?.controller === controller) starting.current = null;
|
|
330
361
|
if (owns(controller)) {
|
|
331
362
|
setBusy(false);
|
|
332
363
|
if (startedItems !== latest.current.items) setRetry((v) => v + 1);
|
|
333
364
|
}
|
|
334
365
|
}
|
|
335
366
|
};
|
|
336
|
-
const
|
|
337
|
-
const
|
|
367
|
+
const ownedResult = port && result?.port === port ? result : null;
|
|
368
|
+
const shownProgress = port && progress?.port === port ? progress : null;
|
|
369
|
+
const current = inventoryReady && ownedResult?.items === items && ownedResult.value.availability === "current" ? ownedResult.value.snapshot : null;
|
|
370
|
+
const available = ownedResult?.value.availability;
|
|
338
371
|
const outcomes = current?.check_breaches ? current.breach_outcomes ?? [] : [];
|
|
339
372
|
const compromised = outcomes.filter((outcome) => outcome.status === "compromised").length;
|
|
340
373
|
const notFound = outcomes.filter((outcome) => outcome.status === "not_found").length;
|
|
341
374
|
const unknown = outcomes.filter((outcome) => outcome.status === "unknown").length;
|
|
342
|
-
const resume =
|
|
375
|
+
const resume = ownedResult && ["failed", "cancelled"].includes(ownedResult.value.execution_status);
|
|
343
376
|
return /* @__PURE__ */ jsxs2("div", { className: "flex h-full min-h-0 flex-col gap-4 overflow-auto p-4", "aria-label": "Password health", children: [
|
|
344
377
|
props.header,
|
|
345
378
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-2", children: [
|
|
@@ -373,9 +406,9 @@ function PasswordHealthView(props) {
|
|
|
373
406
|
/* @__PURE__ */ jsx2(InfoHint, { text: "The breach lookup could not establish a result." })
|
|
374
407
|
] }), children: unknown })
|
|
375
408
|
] }) : null,
|
|
376
|
-
!current &&
|
|
377
|
-
/* @__PURE__ */ jsx2(VaultRow, { label: "Checked", children:
|
|
378
|
-
/* @__PURE__ */ jsx2(VaultRow, { label: "Skipped", children:
|
|
409
|
+
!current && shownProgress ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
410
|
+
/* @__PURE__ */ jsx2(VaultRow, { label: "Checked", children: shownProgress.checked }),
|
|
411
|
+
/* @__PURE__ */ jsx2(VaultRow, { label: "Skipped", children: shownProgress.skipped })
|
|
379
412
|
] }) : null,
|
|
380
413
|
current ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
381
414
|
/* @__PURE__ */ jsx2(VaultRow, { label: "Checked", children: current.checked_subjects.length }),
|
|
@@ -9146,10 +9179,34 @@ function Blank({ children }) {
|
|
|
9146
9179
|
|
|
9147
9180
|
// src/health/api.ts
|
|
9148
9181
|
import { followRuntimeOperationToEndWithApi } from "@ai-matrx/api";
|
|
9149
|
-
import { startPasswordHealthScan, getPasswordHealthScan, resumePasswordHealthScan } from "@ai-matrx/api/account";
|
|
9182
|
+
import { startPasswordHealthScan, getPasswordHealthScan, resumePasswordHealthScan, discoverPasswordHealthScans } from "@ai-matrx/api/account";
|
|
9150
9183
|
import { operationStatus } from "@ai-matrx/api/architecture";
|
|
9151
9184
|
function createHealthPort(api) {
|
|
9152
9185
|
return {
|
|
9186
|
+
discover: async (cursor, signal) => {
|
|
9187
|
+
const stream = await discoverPasswordHealthScans(api, cursor ? { query: { cursor } } : void 0, { signal, totalTimeoutMs: null });
|
|
9188
|
+
let page = null;
|
|
9189
|
+
let ended = false;
|
|
9190
|
+
try {
|
|
9191
|
+
for await (const event of stream) {
|
|
9192
|
+
if (signal.aborted || ended || event.event === "error") throw new Error("Report unavailable");
|
|
9193
|
+
const data = event.data;
|
|
9194
|
+
if (event.event === "completion" && data && typeof data === "object" && "status" in data && data.status !== "success") throw new Error("Report unavailable");
|
|
9195
|
+
if (event.event === "end") {
|
|
9196
|
+
if (!data || typeof data !== "object" || !("reason" in data) || data.reason !== "complete") throw new Error("Report unavailable");
|
|
9197
|
+
ended = true;
|
|
9198
|
+
}
|
|
9199
|
+
if (event.event !== "data") continue;
|
|
9200
|
+
if (!data || typeof data !== "object" || !("type" in data) || data.type !== "vault_password_health_discovery_page") continue;
|
|
9201
|
+
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");
|
|
9202
|
+
page = data;
|
|
9203
|
+
}
|
|
9204
|
+
if (signal.aborted || !ended || !page) throw new Error("Report unavailable");
|
|
9205
|
+
return page;
|
|
9206
|
+
} finally {
|
|
9207
|
+
stream.cancel();
|
|
9208
|
+
}
|
|
9209
|
+
},
|
|
9153
9210
|
start: (requestId, signal, options) => startPasswordHealthScan(api, { body: options.check_breaches ? { check_breaches: true } : {} }, { requestId, signal, totalTimeoutMs: null }),
|
|
9154
9211
|
resume: (executionId, requestId, signal) => resumePasswordHealthScan(api, { path: { execution_id: executionId } }, { requestId, signal, totalTimeoutMs: null }),
|
|
9155
9212
|
read: (executionId, signal) => getPasswordHealthScan(api, { path: { execution_id: executionId } }, { signal }),
|