@rotorsoft/act 1.31.29 → 1.32.0
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/dist/.tsbuildinfo +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
- package/dist/@types/internal/audit.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/@types/internal/drain.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +13 -0
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/audit.d.ts +19 -1
- package/dist/@types/types/audit.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +14 -0
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/@types/types/schemas.d.ts +1 -0
- package/dist/@types/types/schemas.d.ts.map +1 -1
- package/dist/{chunk-34WL4DPW.js → chunk-5NFBMYTY.js} +16 -5
- package/dist/chunk-5NFBMYTY.js.map +1 -0
- package/dist/{chunk-7IBF4FTQ.js → chunk-BI3UNNVA.js} +2 -1
- package/dist/chunk-BI3UNNVA.js.map +1 -0
- package/dist/index.cjs +124 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +111 -15
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +15 -3
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +2 -2
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-34WL4DPW.js.map +0 -1
- package/dist/chunk-7IBF4FTQ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
sleep,
|
|
27
27
|
store,
|
|
28
28
|
validate
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-5NFBMYTY.js";
|
|
30
30
|
import {
|
|
31
31
|
ActorSchema,
|
|
32
32
|
CausationEventSchema,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
pii_split,
|
|
54
54
|
pii_strip,
|
|
55
55
|
sensitive
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-BI3UNNVA.js";
|
|
57
57
|
|
|
58
58
|
// src/signals.ts
|
|
59
59
|
process.once("SIGINT", async (arg) => {
|
|
@@ -213,7 +213,8 @@ var ALL_CATEGORIES = [
|
|
|
213
213
|
"snapshot-drift",
|
|
214
214
|
"routing-health",
|
|
215
215
|
"correlation-gaps",
|
|
216
|
-
"clock-anomalies"
|
|
216
|
+
"clock-anomalies",
|
|
217
|
+
"unreadable-events"
|
|
217
218
|
];
|
|
218
219
|
async function* audit(deps, categories, options = {}) {
|
|
219
220
|
const requested = new Set(categories ?? [...ALL_CATEGORIES]);
|
|
@@ -223,7 +224,9 @@ async function* audit(deps, categories, options = {}) {
|
|
|
223
224
|
);
|
|
224
225
|
const need_stats = passes.some((p) => p.on_stat !== void 0);
|
|
225
226
|
const need_streams = passes.some((p) => p.on_stream !== void 0);
|
|
226
|
-
const need_events = passes.some(
|
|
227
|
+
const need_events = passes.some(
|
|
228
|
+
(p) => p.on_event !== void 0 || p.on_unreadable !== void 0
|
|
229
|
+
);
|
|
227
230
|
if (need_stats) {
|
|
228
231
|
const stats = await deps.store().query_stats(
|
|
229
232
|
{},
|
|
@@ -239,15 +242,57 @@ async function* audit(deps, categories, options = {}) {
|
|
|
239
242
|
});
|
|
240
243
|
}
|
|
241
244
|
if (need_events) {
|
|
242
|
-
await
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
await scan_events_resiliently(
|
|
246
|
+
deps,
|
|
247
|
+
options.query,
|
|
248
|
+
(event) => {
|
|
249
|
+
for (const p of passes) p.on_event?.(event);
|
|
250
|
+
},
|
|
251
|
+
(row) => {
|
|
252
|
+
for (const p of passes) p.on_unreadable?.(row);
|
|
253
|
+
}
|
|
254
|
+
);
|
|
245
255
|
}
|
|
246
256
|
for (const p of passes) await p.finalize?.(deps);
|
|
247
257
|
for (const p of passes) {
|
|
248
258
|
for (const f of p.drain()) yield f;
|
|
249
259
|
}
|
|
250
260
|
}
|
|
261
|
+
async function scan_events_resiliently(deps, query, on_event, on_unreadable) {
|
|
262
|
+
let cursor = query?.after;
|
|
263
|
+
let remaining = query?.limit;
|
|
264
|
+
for (; ; ) {
|
|
265
|
+
let seen = 0;
|
|
266
|
+
try {
|
|
267
|
+
await deps.store().query(
|
|
268
|
+
(event) => {
|
|
269
|
+
seen++;
|
|
270
|
+
cursor = event.id;
|
|
271
|
+
on_event(event);
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
...query,
|
|
275
|
+
after: cursor,
|
|
276
|
+
...remaining !== void 0 && { limit: remaining }
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
return;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
if (query?.backward) throw error;
|
|
282
|
+
let row;
|
|
283
|
+
await deps.store().query(
|
|
284
|
+
(e) => {
|
|
285
|
+
row = { stream: e.stream, event_id: e.id, error };
|
|
286
|
+
},
|
|
287
|
+
{ ...query, after: cursor, limit: 1, with_pii: false }
|
|
288
|
+
);
|
|
289
|
+
if (!row) throw error;
|
|
290
|
+
on_unreadable(row);
|
|
291
|
+
if (remaining !== void 0) remaining -= seen;
|
|
292
|
+
cursor = row.event_id;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
251
296
|
var make_schema_pass = (deps) => {
|
|
252
297
|
const findings = [];
|
|
253
298
|
return {
|
|
@@ -612,6 +657,22 @@ function restart_is_supported(deps, head_event_name) {
|
|
|
612
657
|
const state2 = deps.event_to_state.get(head_event_name);
|
|
613
658
|
return state2?.snap !== void 0;
|
|
614
659
|
}
|
|
660
|
+
function make_unreadable_events_pass() {
|
|
661
|
+
const findings = [];
|
|
662
|
+
return {
|
|
663
|
+
category: "unreadable-events",
|
|
664
|
+
on_unreadable({ stream, event_id, error }) {
|
|
665
|
+
findings.push({
|
|
666
|
+
category: "unreadable-events",
|
|
667
|
+
stream,
|
|
668
|
+
event_id,
|
|
669
|
+
reason: "pii_decrypt_failed",
|
|
670
|
+
error
|
|
671
|
+
});
|
|
672
|
+
},
|
|
673
|
+
drain: () => findings
|
|
674
|
+
};
|
|
675
|
+
}
|
|
615
676
|
var PASS_FACTORIES = {
|
|
616
677
|
schema: make_schema_pass,
|
|
617
678
|
"deprecated-load": make_deprecated_load_pass,
|
|
@@ -621,7 +682,8 @@ var PASS_FACTORIES = {
|
|
|
621
682
|
"snapshot-drift": make_snapshot_drift_pass,
|
|
622
683
|
"routing-health": make_routing_health_pass,
|
|
623
684
|
"correlation-gaps": make_correlation_gaps_pass,
|
|
624
|
-
"clock-anomalies": make_clock_anomalies_pass
|
|
685
|
+
"clock-anomalies": make_clock_anomalies_pass,
|
|
686
|
+
"unreadable-events": make_unreadable_events_pass
|
|
625
687
|
};
|
|
626
688
|
|
|
627
689
|
// src/internal/autoclose-policy.ts
|
|
@@ -1752,7 +1814,19 @@ var CorrelateCycle = class {
|
|
|
1752
1814
|
}
|
|
1753
1815
|
}
|
|
1754
1816
|
},
|
|
1755
|
-
|
|
1817
|
+
// Decline the sensitive payload: this scan reads `name`/`stream`/`id`
|
|
1818
|
+
// to resolve reaction targets and throws the rest away. Asking for a
|
|
1819
|
+
// payload it discards made one unreadable row stop EVERY stream's
|
|
1820
|
+
// reactions — correlate is the sole producer of the work mark, so a
|
|
1821
|
+
// decrypt failure here strands the whole app with nothing blocked and
|
|
1822
|
+
// nothing naming the row (#1675).
|
|
1823
|
+
//
|
|
1824
|
+
// A dynamic `.to(event => …)` resolver therefore sees `pii: null`.
|
|
1825
|
+
// That is deliberate and is itself a fix: correlate runs actor-less,
|
|
1826
|
+
// so handing a resolver decrypted plaintext is un-gated disclosure —
|
|
1827
|
+
// the defect #1673 corrected on the drain return and #1277 before it.
|
|
1828
|
+
// `data` already carries no sensitive keys; nothing merges them here.
|
|
1829
|
+
{ ...query, after, with_pii: false }
|
|
1756
1830
|
);
|
|
1757
1831
|
const streams = [];
|
|
1758
1832
|
for (const [stream, entry] of correlated) {
|
|
@@ -2094,12 +2168,23 @@ async function fetch(leased, eventLimit) {
|
|
|
2094
2168
|
leased.map(async ({ stream, source, at, lagging }) => {
|
|
2095
2169
|
const events = [];
|
|
2096
2170
|
const stream_exact = source !== void 0 && is_literal_source(source) ? true : void 0;
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2171
|
+
try {
|
|
2172
|
+
await store().query((e) => events.push(e), {
|
|
2173
|
+
stream: source,
|
|
2174
|
+
stream_exact,
|
|
2175
|
+
after: at,
|
|
2176
|
+
limit: eventLimit
|
|
2177
|
+
});
|
|
2178
|
+
} catch (error) {
|
|
2179
|
+
return {
|
|
2180
|
+
stream,
|
|
2181
|
+
source,
|
|
2182
|
+
at,
|
|
2183
|
+
lagging,
|
|
2184
|
+
events: [],
|
|
2185
|
+
error: error?.message ?? String(error)
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2103
2188
|
return { stream, source, at, lagging, events };
|
|
2104
2189
|
})
|
|
2105
2190
|
);
|
|
@@ -2754,6 +2839,17 @@ async function run_drain_cycle(ops, registry, batch_handlers, misrouted, store_f
|
|
|
2754
2839
|
const handled = await Promise.all(
|
|
2755
2840
|
leased.map((lease) => {
|
|
2756
2841
|
const entry = fetch_map.get(lease.stream);
|
|
2842
|
+
if (entry.fetch.error !== void 0) {
|
|
2843
|
+
const error = `Fetch failed for ${lease.stream}: ${entry.fetch.error}`;
|
|
2844
|
+
log().error(error);
|
|
2845
|
+
const failed = {
|
|
2846
|
+
lease,
|
|
2847
|
+
handled: 0,
|
|
2848
|
+
acked_at: lease.at,
|
|
2849
|
+
error
|
|
2850
|
+
};
|
|
2851
|
+
return Promise.resolve(failed);
|
|
2852
|
+
}
|
|
2757
2853
|
const at = entry.fetch.events.at(-1)?.id || fetch_window_at;
|
|
2758
2854
|
const { payloads } = entry;
|
|
2759
2855
|
const exhausted = budget_exhausted(
|