@rotorsoft/act 1.37.6 → 1.37.8
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/autoclose-reaction.d.ts +8 -0
- package/dist/@types/internal/autoclose-reaction.d.ts.map +1 -1
- package/dist/@types/internal/close-cycle.d.ts.map +1 -1
- package/dist/@types/internal/date-reviver.d.ts +6 -3
- package/dist/@types/internal/date-reviver.d.ts.map +1 -1
- package/dist/@types/internal/drain-ops.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/reaction-dispatch.d.ts +6 -0
- package/dist/@types/internal/reaction-dispatch.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +5 -6
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/utils.d.ts +18 -1
- package/dist/@types/utils.d.ts.map +1 -1
- package/dist/{chunk-PRDX3HP6.cjs → chunk-4UWU5FAN.cjs} +25 -24
- package/dist/chunk-4UWU5FAN.cjs.map +1 -0
- package/dist/{chunk-H6KVPVP4.cjs → chunk-BCA423WP.cjs} +1 -1
- package/dist/chunk-BCA423WP.cjs.map +1 -0
- package/dist/{chunk-V5ZB54DC.js → chunk-I5RF2NFR.js} +1 -1
- package/dist/chunk-I5RF2NFR.js.map +1 -0
- package/dist/{chunk-HXW3TPP6.js → chunk-TSDQDT4S.js} +13 -12
- package/dist/chunk-TSDQDT4S.js.map +1 -0
- package/dist/index.cjs +1665 -1608
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1276 -1219
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +4 -4
- package/dist/test/index.js +2 -2
- package/dist/types/index.cjs +2 -2
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-H6KVPVP4.cjs.map +0 -1
- package/dist/chunk-HXW3TPP6.js.map +0 -1
- package/dist/chunk-PRDX3HP6.cjs.map +0 -1
- package/dist/chunk-V5ZB54DC.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
var _chunkPRDX3HP6cjs = require('./chunk-PRDX3HP6.cjs');
|
|
44
43
|
|
|
45
44
|
|
|
45
|
+
var _chunk4UWU5FANcjs = require('./chunk-4UWU5FAN.cjs');
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
|
|
@@ -74,24 +74,26 @@ var _chunkPRDX3HP6cjs = require('./chunk-PRDX3HP6.cjs');
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
var _chunkBCA423WPcjs = require('./chunk-BCA423WP.cjs');
|
|
78
80
|
|
|
79
81
|
// src/signals.ts
|
|
80
82
|
process.once("SIGINT", async (arg) => {
|
|
81
|
-
|
|
82
|
-
await
|
|
83
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).info(arg, "SIGINT");
|
|
84
|
+
await _chunk4UWU5FANcjs.disposeAndExit.call(void 0, "EXIT");
|
|
83
85
|
});
|
|
84
86
|
process.once("SIGTERM", async (arg) => {
|
|
85
|
-
|
|
86
|
-
await
|
|
87
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).info(arg, "SIGTERM");
|
|
88
|
+
await _chunk4UWU5FANcjs.disposeAndExit.call(void 0, "EXIT");
|
|
87
89
|
});
|
|
88
90
|
process.once("uncaughtException", async (arg) => {
|
|
89
|
-
|
|
90
|
-
await
|
|
91
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).error(arg, "Uncaught Exception");
|
|
92
|
+
await _chunk4UWU5FANcjs.disposeAndExit.call(void 0, "ERROR");
|
|
91
93
|
});
|
|
92
94
|
process.once("unhandledRejection", async (arg) => {
|
|
93
|
-
|
|
94
|
-
await
|
|
95
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).error(arg, "Unhandled Rejection");
|
|
96
|
+
await _chunk4UWU5FANcjs.disposeAndExit.call(void 0, "ERROR");
|
|
95
97
|
});
|
|
96
98
|
|
|
97
99
|
// src/act.ts
|
|
@@ -199,7 +201,7 @@ async function* audit(deps, categories, options = {}) {
|
|
|
199
201
|
if (need_stats) {
|
|
200
202
|
const stats = await deps.store().query_stats(
|
|
201
203
|
{},
|
|
202
|
-
{ count: true, names: true, exclude: [
|
|
204
|
+
{ count: true, names: true, exclude: [_chunkBCA423WPcjs.SNAP_EVENT] }
|
|
203
205
|
);
|
|
204
206
|
for (const [stream, s] of stats) {
|
|
205
207
|
for (const p of passes) _optionalChain([p, 'access', _4 => _4.on_stat, 'optionalCall', _5 => _5(stream, s)]);
|
|
@@ -281,7 +283,7 @@ var make_schema_pass = (deps) => {
|
|
|
281
283
|
return;
|
|
282
284
|
}
|
|
283
285
|
const schema = state2.events[name];
|
|
284
|
-
const sensitive2 =
|
|
286
|
+
const sensitive2 = _chunkBCA423WPcjs.pii_fields.call(void 0, schema);
|
|
285
287
|
let parse_schema = schema;
|
|
286
288
|
if (sensitive2.length > 0) {
|
|
287
289
|
const omitter = schema.omit;
|
|
@@ -415,8 +417,10 @@ var make_restart_candidate_pass = (deps, options) => {
|
|
|
415
417
|
{
|
|
416
418
|
stream,
|
|
417
419
|
stream_exact: true,
|
|
418
|
-
names: [
|
|
419
|
-
with_snaps: true
|
|
420
|
+
names: [_chunkBCA423WPcjs.SNAP_EVENT],
|
|
421
|
+
with_snaps: true,
|
|
422
|
+
// From the start: on its own, `with_snaps` resumes at the latest.
|
|
423
|
+
after: -1
|
|
420
424
|
}
|
|
421
425
|
);
|
|
422
426
|
findings.push({
|
|
@@ -573,7 +577,7 @@ var make_correlation_gaps_pass = () => {
|
|
|
573
577
|
seen_ids.add(e.id);
|
|
574
578
|
const causation = _optionalChain([e, 'access', _31 => _31.meta, 'optionalAccess', _32 => _32.causation]);
|
|
575
579
|
const parent_id = _optionalChain([causation, 'optionalAccess', _33 => _33.event, 'optionalAccess', _34 => _34.id]);
|
|
576
|
-
if (parent_id !== void 0) {
|
|
580
|
+
if (parent_id !== void 0 && e.name !== _chunkBCA423WPcjs.TOMBSTONE_EVENT) {
|
|
577
581
|
checks.push({ stream: e.stream, id: e.id, parent_id });
|
|
578
582
|
}
|
|
579
583
|
},
|
|
@@ -795,674 +799,303 @@ function classify_registry(registry, states) {
|
|
|
795
799
|
};
|
|
796
800
|
}
|
|
797
801
|
|
|
798
|
-
// src/internal/
|
|
799
|
-
var
|
|
800
|
-
var
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
await correlate(CLOSE_CATCH_UP_LIMIT);
|
|
806
|
-
if (cursor.checkpoint <= before) break;
|
|
807
|
-
}
|
|
808
|
-
return cursor.checkpoint;
|
|
802
|
+
// src/internal/autoclose-policy.ts
|
|
803
|
+
var _zod = require('zod');
|
|
804
|
+
var DAY_MS = 864e5;
|
|
805
|
+
var MIN_AFTER_DAYS = 1 / 1440;
|
|
806
|
+
var MIN_KEEP_DAYS = 1;
|
|
807
|
+
function days_after(date, days) {
|
|
808
|
+
return new Date(date.getTime() + days * DAY_MS);
|
|
809
809
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
810
|
+
function days_before_now(days) {
|
|
811
|
+
return new Date(Date.now() - days * DAY_MS);
|
|
812
|
+
}
|
|
813
|
+
var window_schema = (field, min_days, floor) => _zod.z.object({
|
|
814
|
+
days: _zod.z.number({ message: `autocloses: ${field}.days must be a number` }).positive(`autocloses: ${field}.days must be > 0`)
|
|
815
|
+
}).refine((o) => o.days >= min_days, {
|
|
816
|
+
message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`
|
|
817
|
+
});
|
|
818
|
+
var AfterSchema = window_schema("after", MIN_AFTER_DAYS, "one minute");
|
|
819
|
+
var KeepSchema = window_schema("keep", MIN_KEEP_DAYS, "one day");
|
|
820
|
+
var IsSchema = _zod.z.union([
|
|
821
|
+
_zod.z.string().min(1, "autocloses: is must be a non-empty event name"),
|
|
822
|
+
_zod.z.array(
|
|
823
|
+
_zod.z.string().min(1, "autocloses: is entries must be non-empty event names")
|
|
824
|
+
).min(1, "autocloses: is must include at least one event name").readonly()
|
|
825
|
+
]);
|
|
826
|
+
var ReachesSchema = _zod.z.number({ message: "autocloses: reaches must be a number" }).int("autocloses: reaches must be an integer").min(1, "autocloses: reaches must be >= 1");
|
|
827
|
+
var OrBlockSchema = _zod.z.object({
|
|
828
|
+
after: AfterSchema.optional(),
|
|
829
|
+
is: IsSchema.optional(),
|
|
830
|
+
reaches: ReachesSchema.optional()
|
|
831
|
+
}).strict().refine(
|
|
832
|
+
(o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0,
|
|
833
|
+
{
|
|
834
|
+
message: "autocloses: `or` block must include at least one of after / is / reaches"
|
|
822
835
|
}
|
|
823
|
-
|
|
824
|
-
var
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
836
|
+
);
|
|
837
|
+
var AutoclosePolicySchema = _zod.z.object({
|
|
838
|
+
after: AfterSchema.optional(),
|
|
839
|
+
is: IsSchema.optional(),
|
|
840
|
+
reaches: ReachesSchema.optional(),
|
|
841
|
+
or: OrBlockSchema.optional(),
|
|
842
|
+
keep: KeepSchema.optional()
|
|
843
|
+
}).strict().refine(
|
|
844
|
+
(o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0 || o.or !== void 0 || o.keep !== void 0,
|
|
845
|
+
{
|
|
846
|
+
message: "autocloses: at least one of after / is / reaches / or / keep must be specified \u2014 empty `{}` is a misconfiguration"
|
|
832
847
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
);
|
|
836
|
-
const full = [...target_map.values()].filter((t) => t.before === void 0);
|
|
837
|
-
const skipped = [];
|
|
838
|
-
const windowed_result = windowed.length ? await run_windowed_closes(windowed, deps, skipped) : /* @__PURE__ */ new Map();
|
|
839
|
-
if (!full.length) return { truncated: windowed_result, skipped };
|
|
840
|
-
const truncated = await with_stream_locks(
|
|
841
|
-
full.map((t) => t.stream),
|
|
842
|
-
deps,
|
|
843
|
-
() => run_full_closes(full, target_map, deps, skipped)
|
|
844
|
-
);
|
|
845
|
-
const retired = [...truncated.entries()].filter(([, r]) => r.committed.name === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT).map(([stream]) => stream);
|
|
846
|
-
if (retired.length) _optionalChain([deps, 'access', _42 => _42.forget_subscribed, 'optionalCall', _43 => _43(retired)]);
|
|
847
|
-
for (const [stream, entry] of windowed_result) truncated.set(stream, entry);
|
|
848
|
-
return { truncated, skipped };
|
|
848
|
+
);
|
|
849
|
+
function compile_after(after) {
|
|
850
|
+
return (_stream, head) => days_after(head.created, after.days) <= /* @__PURE__ */ new Date();
|
|
849
851
|
}
|
|
850
|
-
function
|
|
851
|
-
const
|
|
852
|
-
return
|
|
853
|
-
(inner, stream) => () => with_lock(stream, inner),
|
|
854
|
-
work
|
|
855
|
-
)();
|
|
852
|
+
function compile_is(is) {
|
|
853
|
+
const set = new Set(typeof is === "string" ? [is] : is);
|
|
854
|
+
return (_stream, head) => set.has(head.name);
|
|
856
855
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
const streams = full.map((t) => t.stream);
|
|
860
|
-
const stream_info = await scan_stream_heads(streams);
|
|
861
|
-
for (const target of full) {
|
|
862
|
-
if (!target.restart) continue;
|
|
863
|
-
const info = stream_info.get(target.stream);
|
|
864
|
-
if (!info) continue;
|
|
865
|
-
const owner = deps.event_to_state.get(info.last_event_name);
|
|
866
|
-
if (_optionalChain([owner, 'optionalAccess', _44 => _44.pii_aware])) {
|
|
867
|
-
deps.logger.error(
|
|
868
|
-
`Refusing to close "${target.stream}" with restart: state "${owner.name}" carries sensitive fields, so a restart seed would persist redacted values while deleting the originals. Close it without restart to retire the stream, or leave it open.`
|
|
869
|
-
);
|
|
870
|
-
skipped.push(target.stream);
|
|
871
|
-
stream_info.delete(target.stream);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
const safe = await partition_by_safety(
|
|
875
|
-
stream_info,
|
|
876
|
-
deps.reactive,
|
|
877
|
-
skipped,
|
|
878
|
-
_nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
|
|
879
|
-
deps.catch_up_correlation
|
|
880
|
-
);
|
|
881
|
-
if (!safe.length) return none;
|
|
882
|
-
const { guarded, guard_events } = await guard_with_tombstones(
|
|
883
|
-
safe,
|
|
884
|
-
stream_info,
|
|
885
|
-
deps.correlation,
|
|
886
|
-
deps.tombstone,
|
|
887
|
-
skipped
|
|
888
|
-
);
|
|
889
|
-
if (!guarded.length) return none;
|
|
890
|
-
const seed_states = await load_restart_seeds(
|
|
891
|
-
guarded,
|
|
892
|
-
target_map,
|
|
893
|
-
stream_info,
|
|
894
|
-
deps.event_to_state,
|
|
895
|
-
deps.load,
|
|
896
|
-
deps.logger
|
|
897
|
-
);
|
|
898
|
-
await run_archive_callbacks(guarded, target_map);
|
|
899
|
-
const still_guarded = await heads_still_guarded(
|
|
900
|
-
guarded,
|
|
901
|
-
guard_events,
|
|
902
|
-
skipped
|
|
903
|
-
);
|
|
904
|
-
if (!still_guarded.length) return none;
|
|
905
|
-
return truncate_and_warm_cache(
|
|
906
|
-
still_guarded,
|
|
907
|
-
seed_states,
|
|
908
|
-
guard_events,
|
|
909
|
-
deps.correlation
|
|
910
|
-
);
|
|
856
|
+
function compile_reaches(reaches) {
|
|
857
|
+
return (_stream, _head, count) => count >= reaches;
|
|
911
858
|
}
|
|
912
|
-
|
|
913
|
-
const
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
) : /* @__PURE__ */ new Map();
|
|
919
|
-
const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, work) => work())));
|
|
920
|
-
const truncated = /* @__PURE__ */ new Map();
|
|
921
|
-
for (const t of windowed) {
|
|
922
|
-
const entry = await with_lock(t.stream, async () => {
|
|
923
|
-
const max_id = min_at.get(t.stream);
|
|
924
|
-
if (!await windowed_prune_pending(t.stream, t.before, max_id))
|
|
925
|
-
return void 0;
|
|
926
|
-
if (t.archive) await t.archive();
|
|
927
|
-
const result = await _chunkPRDX3HP6cjs.store.call(void 0, ).truncate([
|
|
928
|
-
{ stream: t.stream, before: t.before, max_id }
|
|
929
|
-
]);
|
|
930
|
-
return result.get(t.stream);
|
|
931
|
-
});
|
|
932
|
-
if (entry) truncated.set(t.stream, entry);
|
|
933
|
-
else skipped.push(t.stream);
|
|
934
|
-
}
|
|
935
|
-
return truncated;
|
|
859
|
+
function policy_min_after_days(options) {
|
|
860
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
861
|
+
const windows = [];
|
|
862
|
+
if (parsed.after) windows.push(parsed.after.days);
|
|
863
|
+
if (_optionalChain([parsed, 'access', _42 => _42.or, 'optionalAccess', _43 => _43.after])) windows.push(parsed.or.after.days);
|
|
864
|
+
return windows.length ? Math.min(...windows) : void 0;
|
|
936
865
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
await _chunkPRDX3HP6cjs.store.call(void 0, ).query(
|
|
941
|
-
(event) => {
|
|
942
|
-
if (min_id === void 0 || event.id < min_id) min_id = event.id;
|
|
943
|
-
if (event.name === _chunkH6KVPVP4cjs.SNAP_EVENT && event.created < before && (max_id === void 0 || event.id <= max_id) && (boundary_id === void 0 || event.id > boundary_id))
|
|
944
|
-
boundary_id = event.id;
|
|
945
|
-
},
|
|
946
|
-
{ stream, stream_exact: true, with_snaps: true, after: -1 }
|
|
947
|
-
);
|
|
948
|
-
return boundary_id !== void 0 && min_id < boundary_id;
|
|
866
|
+
function policy_after_windows(options) {
|
|
867
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
868
|
+
return [parsed.after, _optionalChain([parsed, 'access', _44 => _44.or, 'optionalAccess', _45 => _45.after])].flatMap((w) => w ? [w.days] : []);
|
|
949
869
|
}
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
await walk_streams(
|
|
954
|
-
_chunkPRDX3HP6cjs.store.call(void 0, ),
|
|
955
|
-
(position) => {
|
|
956
|
-
const pending = position.correlated_at === void 0 || position.at < position.correlated_at;
|
|
957
|
-
const cap = pending ? position.at : Math.max(position.at, checkpoint);
|
|
958
|
-
for (const stream of streams) {
|
|
959
|
-
if (matches(position.source, stream)) {
|
|
960
|
-
const prev = min_at.get(stream);
|
|
961
|
-
if (prev === void 0 || cap < prev) min_at.set(stream, cap);
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
},
|
|
965
|
-
{ limit: page_size, source_matches: streams }
|
|
966
|
-
);
|
|
967
|
-
return min_at;
|
|
870
|
+
function policy_keep_days(options) {
|
|
871
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
872
|
+
return _optionalChain([parsed, 'access', _46 => _46.keep, 'optionalAccess', _47 => _47.days]);
|
|
968
873
|
}
|
|
969
|
-
function
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
874
|
+
function compile_autoclose_policy(options) {
|
|
875
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
876
|
+
const and_preds = [];
|
|
877
|
+
if (parsed.after) and_preds.push(compile_after(parsed.after));
|
|
878
|
+
if (parsed.is) and_preds.push(compile_is(parsed.is));
|
|
879
|
+
if (parsed.reaches) and_preds.push(compile_reaches(parsed.reaches));
|
|
880
|
+
const or_preds = [];
|
|
881
|
+
if (parsed.or) {
|
|
882
|
+
if (parsed.or.after) or_preds.push(compile_after(parsed.or.after));
|
|
883
|
+
if (parsed.or.is) or_preds.push(compile_is(parsed.or.is));
|
|
884
|
+
if (parsed.or.reaches) or_preds.push(compile_reaches(parsed.or.reaches));
|
|
885
|
+
}
|
|
886
|
+
return (stream, head, count) => {
|
|
887
|
+
if (and_preds.length > 0 && and_preds.every((p) => p(stream, head, count))) {
|
|
888
|
+
return true;
|
|
977
889
|
}
|
|
978
|
-
|
|
890
|
+
if (or_preds.some((p) => p(stream, head, count))) {
|
|
891
|
+
return true;
|
|
892
|
+
}
|
|
893
|
+
return false;
|
|
979
894
|
};
|
|
980
895
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
for (const [stream, { head }] of domain_heads) {
|
|
991
|
-
const marker_head = _optionalChain([stats, 'access', _45 => _45.get, 'call', _46 => _46(stream), 'optionalAccess', _47 => _47.head]);
|
|
992
|
-
const interrupted = _optionalChain([marker_head, 'optionalAccess', _48 => _48.name]) === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT;
|
|
993
|
-
out.set(stream, {
|
|
994
|
-
max_id: head.id,
|
|
995
|
-
version: true_heads.get(stream).head.version,
|
|
996
|
-
last_event_name: head.name,
|
|
997
|
-
...interrupted ? { resumed_guard: { id: marker_head.id } } : {}
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
return out;
|
|
1001
|
-
}
|
|
1002
|
-
async function partition_by_safety(stream_info, reactive, skipped, page_size, catch_up_correlation2) {
|
|
1003
|
-
if (!reactive) return [...stream_info.keys()];
|
|
1004
|
-
let needed = -1;
|
|
1005
|
-
for (const info of stream_info.values())
|
|
1006
|
-
needed = Math.max(needed, info.max_id);
|
|
1007
|
-
const checkpoint = await catch_up_correlation2(needed);
|
|
1008
|
-
const uncorrelated = /* @__PURE__ */ new Set();
|
|
1009
|
-
for (const [stream, info] of stream_info) {
|
|
1010
|
-
if (checkpoint < info.max_id) uncorrelated.add(stream);
|
|
1011
|
-
}
|
|
1012
|
-
const pending_set = /* @__PURE__ */ new Set();
|
|
1013
|
-
const matches = source_matcher();
|
|
1014
|
-
const targets = [...stream_info.keys()];
|
|
1015
|
-
await walk_streams(
|
|
1016
|
-
_chunkPRDX3HP6cjs.store.call(void 0, ),
|
|
1017
|
-
(position) => {
|
|
1018
|
-
const has_work = position.correlated_at !== void 0 && position.at < position.correlated_at;
|
|
1019
|
-
if (!has_work) return;
|
|
1020
|
-
for (const [stream, info] of stream_info) {
|
|
1021
|
-
if (matches(position.source, stream) && position.at < info.max_id)
|
|
1022
|
-
pending_set.add(stream);
|
|
1023
|
-
}
|
|
1024
|
-
},
|
|
1025
|
-
{ limit: page_size, source_matches: targets }
|
|
1026
|
-
);
|
|
1027
|
-
const safe = [];
|
|
1028
|
-
for (const [stream] of stream_info) {
|
|
1029
|
-
if (pending_set.has(stream) || uncorrelated.has(stream))
|
|
1030
|
-
skipped.push(stream);
|
|
1031
|
-
else safe.push(stream);
|
|
1032
|
-
}
|
|
1033
|
-
return safe;
|
|
896
|
+
|
|
897
|
+
// src/internal/autoclose-window.ts
|
|
898
|
+
function hour_in_zone(now, timeZone) {
|
|
899
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
900
|
+
timeZone,
|
|
901
|
+
hour: "2-digit",
|
|
902
|
+
hourCycle: "h23"
|
|
903
|
+
}).formatToParts(now);
|
|
904
|
+
return Number(_optionalChain([parts, 'access', _48 => _48.find, 'call', _49 => _49((p) => p.type === "hour"), 'optionalAccess', _50 => _50.value]));
|
|
1034
905
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
const guard_events = /* @__PURE__ */ new Map();
|
|
1038
|
-
await Promise.all(
|
|
1039
|
-
safe.map(async (stream) => {
|
|
1040
|
-
const info = stream_info.get(stream);
|
|
1041
|
-
if (info.resumed_guard) {
|
|
1042
|
-
guarded.push(stream);
|
|
1043
|
-
guard_events.set(stream, { id: info.resumed_guard.id, stream });
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
const committed = await tombstone2(stream, info.version, correlation);
|
|
1047
|
-
if (committed) {
|
|
1048
|
-
guarded.push(stream);
|
|
1049
|
-
guard_events.set(stream, { id: committed.id, stream });
|
|
1050
|
-
} else {
|
|
1051
|
-
skipped.push(stream);
|
|
1052
|
-
}
|
|
1053
|
-
})
|
|
1054
|
-
);
|
|
1055
|
-
return { guarded, guard_events };
|
|
906
|
+
function hour_in_range(hour, start, end) {
|
|
907
|
+
return start < end ? hour >= start && hour < end : hour >= start || hour < end;
|
|
1056
908
|
}
|
|
1057
|
-
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const owner_state = event_to_state.get(last_event_name);
|
|
1063
|
-
if (!owner_state) {
|
|
1064
|
-
logger.error(
|
|
1065
|
-
`Cannot seed restart for "${stream}": no registered state owns event "${last_event_name}". Stream will be tombstoned instead.`
|
|
1066
|
-
);
|
|
1067
|
-
return;
|
|
1068
|
-
}
|
|
1069
|
-
const snap2 = await load2(owner_state, { stream });
|
|
1070
|
-
seed_states.set(stream, snap2.state);
|
|
1071
|
-
})
|
|
1072
|
-
);
|
|
1073
|
-
return seed_states;
|
|
909
|
+
function is_dst_gap_open(now, timeZone, start) {
|
|
910
|
+
const hour = hour_in_zone(now, timeZone);
|
|
911
|
+
if (hour <= start) return false;
|
|
912
|
+
const prev = hour_in_zone(new Date(now.getTime() - 36e5), timeZone);
|
|
913
|
+
return prev === start - 1 && hour === start + 1;
|
|
1074
914
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
915
|
+
function in_autoclose_window(window, now) {
|
|
916
|
+
if (!window) return true;
|
|
917
|
+
const hour = hour_in_zone(now, window.timeZone);
|
|
918
|
+
return hour_in_range(hour, window.start, window.end) || is_dst_gap_open(now, window.timeZone, window.start);
|
|
919
|
+
}
|
|
920
|
+
function next_window_open(window, now) {
|
|
921
|
+
const start_ms = now.getTime();
|
|
922
|
+
for (let h = 0; h <= 48; h++) {
|
|
923
|
+
const candidate = new Date(start_ms + h * 36e5);
|
|
924
|
+
if (hour_in_zone(candidate, window.timeZone) === window.start)
|
|
925
|
+
return candidate;
|
|
926
|
+
const boundary = new Date(
|
|
927
|
+
candidate.getTime() - candidate.getTime() % 36e5
|
|
928
|
+
);
|
|
929
|
+
if (boundary.getTime() >= start_ms && is_dst_gap_open(boundary, window.timeZone, window.start))
|
|
930
|
+
return boundary;
|
|
1079
931
|
}
|
|
932
|
+
return new Date(start_ms + 864e5);
|
|
1080
933
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
934
|
+
|
|
935
|
+
// src/internal/defer-config.ts
|
|
936
|
+
|
|
937
|
+
var DeferDurationSchema = _zod.z.object({
|
|
938
|
+
days: _zod.z.number().positive().optional(),
|
|
939
|
+
hours: _zod.z.number().positive().optional(),
|
|
940
|
+
minutes: _zod.z.number().positive().optional()
|
|
941
|
+
}).strict().refine((d) => d.days != null || d.hours != null || d.minutes != null, {
|
|
942
|
+
message: "defer: a duration needs at least one of days, hours, or minutes"
|
|
943
|
+
});
|
|
944
|
+
var DeferWhenSchema = _zod.z.object({
|
|
945
|
+
after: DeferDurationSchema.optional(),
|
|
946
|
+
at: _zod.z.date().optional()
|
|
947
|
+
}).strict().refine((w) => w.after === void 0 !== (w.at === void 0), {
|
|
948
|
+
message: "defer: specify exactly one of `after` or `at`"
|
|
949
|
+
});
|
|
950
|
+
function duration_ms(d) {
|
|
951
|
+
return (_nullishCoalesce(d.days, () => ( 0))) * 864e5 + (_nullishCoalesce(d.hours, () => ( 0))) * 36e5 + (_nullishCoalesce(d.minutes, () => ( 0))) * 6e4;
|
|
1089
952
|
}
|
|
1090
|
-
|
|
1091
|
-
const
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
guarded.map(async (stream) => {
|
|
1108
|
-
const entry = truncated.get(stream);
|
|
1109
|
-
const state2 = seed_states.get(stream);
|
|
1110
|
-
if (state2 && entry) {
|
|
1111
|
-
await _chunkPRDX3HP6cjs.cache.call(void 0, ).set(stream, {
|
|
1112
|
-
stream,
|
|
1113
|
-
state: state2,
|
|
1114
|
-
version: entry.committed.version,
|
|
1115
|
-
event_id: entry.committed.id,
|
|
1116
|
-
patches: 0,
|
|
1117
|
-
snaps: 1
|
|
1118
|
-
});
|
|
1119
|
-
} else {
|
|
1120
|
-
await _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(stream);
|
|
1121
|
-
}
|
|
1122
|
-
})
|
|
1123
|
-
);
|
|
1124
|
-
return truncated;
|
|
953
|
+
function resolve_defer_at(when, event) {
|
|
954
|
+
const parsed = DeferWhenSchema.parse(when);
|
|
955
|
+
if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);
|
|
956
|
+
return parsed.at.getTime();
|
|
957
|
+
}
|
|
958
|
+
function assert_defer_when(when) {
|
|
959
|
+
DeferWhenSchema.parse(when);
|
|
960
|
+
}
|
|
961
|
+
function make_deferred(handler, schedule) {
|
|
962
|
+
const call = handler;
|
|
963
|
+
const deferred = async (event, stream, app) => {
|
|
964
|
+
const when = typeof schedule === "function" ? schedule(event) : schedule;
|
|
965
|
+
if (Date.now() < resolve_defer_at(when, event)) throw new (0, _chunkBCA423WPcjs.DeferSignal)(when);
|
|
966
|
+
return call(event, stream, app);
|
|
967
|
+
};
|
|
968
|
+
Object.defineProperty(deferred, "name", { value: handler.name });
|
|
969
|
+
return deferred;
|
|
1125
970
|
}
|
|
1126
971
|
|
|
1127
|
-
// src/internal/
|
|
972
|
+
// src/internal/drain-cycle.ts
|
|
1128
973
|
var _crypto = require('crypto');
|
|
1129
974
|
|
|
1130
|
-
// src/internal/
|
|
1131
|
-
function
|
|
1132
|
-
if (
|
|
1133
|
-
|
|
1134
|
-
|
|
975
|
+
// src/internal/backoff.ts
|
|
976
|
+
function compute_backoff_delay(retry, opts) {
|
|
977
|
+
if (!opts || opts.baseMs <= 0) return 0;
|
|
978
|
+
const r = Math.max(0, retry);
|
|
979
|
+
let delay;
|
|
980
|
+
switch (opts.strategy) {
|
|
981
|
+
case "fixed":
|
|
982
|
+
delay = opts.baseMs;
|
|
983
|
+
break;
|
|
984
|
+
case "linear":
|
|
985
|
+
delay = opts.baseMs * (r + 1);
|
|
986
|
+
break;
|
|
987
|
+
case "exponential":
|
|
988
|
+
delay = opts.baseMs * 2 ** r;
|
|
989
|
+
if (opts.maxMs !== void 0) delay = Math.min(delay, opts.maxMs);
|
|
990
|
+
break;
|
|
991
|
+
default: {
|
|
992
|
+
const _never = opts.strategy;
|
|
993
|
+
throw new Error(`unknown backoff strategy: ${String(_never)}`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
if (opts.jitter) delay = delay * (0.5 + Math.random());
|
|
997
|
+
return Math.max(0, Math.floor(delay));
|
|
1135
998
|
}
|
|
1136
999
|
|
|
1137
|
-
// src/internal/
|
|
1138
|
-
var
|
|
1139
|
-
var
|
|
1140
|
-
|
|
1141
|
-
const shape = Object.keys(events).filter((name) => events[name].reactions.size > 0).sort().map((name) => [name, [...events[name].reactions.keys()].sort()]);
|
|
1142
|
-
return _crypto.createHash.call(void 0, "sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 32);
|
|
1143
|
-
};
|
|
1144
|
-
var PATTERN_CACHE_SIZE = 32;
|
|
1145
|
-
function report_undeclared_lane(seen, handler, target, lane, declared) {
|
|
1146
|
-
report_once(
|
|
1147
|
-
seen,
|
|
1148
|
-
`lane|${handler}|${lane}`,
|
|
1149
|
-
`Reaction "${handler}" resolved onto undeclared lane "${lane}" \u2014 for example target "${target}". Declared lanes: ${[...declared].map((l) => `"${l}"`).join(", ")}. No controller claims it, so the stream would never drain \u2014 running it on "default" instead. The equivalent static \`.to({ lane })\` is rejected at build; a dynamic resolver's lane is only knowable here.`
|
|
1150
|
-
);
|
|
1151
|
-
}
|
|
1152
|
-
function report_lane_conflict(seen, handler, target, kept, dropped) {
|
|
1153
|
-
report_once(
|
|
1154
|
-
seen,
|
|
1155
|
-
`conflict|${handler}|${kept}|${dropped}`,
|
|
1156
|
-
`Reaction "${handler}" resolved lane "${dropped}" for a stream already on "${kept}" \u2014 for example "${target}". These are conflicting lane assignments from two dynamic resolutions at equal priority. Keeping "${kept}", the lane it was first discovered on \u2014 re-laning a live stream would move it out from under a worker holding its lease. The reaction resolving "${dropped}" runs inside the "${kept}" lane's budget, and a process restricted to "${dropped}" via onlyLanes never runs it. The equivalent static declaration is rejected at build; align the resolvers, or split the target.`
|
|
1157
|
-
);
|
|
1158
|
-
}
|
|
1159
|
-
var CorrelateCycle = (_class3 = class {
|
|
1160
|
-
__init3() {this._checkpoint = -1}
|
|
1161
|
-
// Lease holder id; per instance, so a restart never inherits a stale claim.
|
|
1162
|
-
__init4() {this._by = _crypto.randomUUID.call(void 0, )}
|
|
1163
|
-
|
|
1164
|
-
// Local expiry of the held lease (0 = none); stale only costs a duplicate scan.
|
|
1165
|
-
__init5() {this._lease_until = 0}
|
|
1166
|
-
// Armed while `_raised` (bumped by a commit or notification) is ahead of
|
|
1167
|
-
// `_lowered` (the raise count the last short page saw). Starts armed.
|
|
1168
|
-
__init6() {this._raised = 1}
|
|
1169
|
-
__init7() {this._lowered = 0}
|
|
1170
|
-
// Bumped by a release (shutdown), so a scan or lease reply that was out
|
|
1171
|
-
// across one writes nothing.
|
|
1172
|
-
__init8() {this._epoch = 0}
|
|
1173
|
-
// Passes in flight: a restore waits for them, and refuses new ones.
|
|
1174
|
-
__init9() {this._passes = /* @__PURE__ */ new Set()}
|
|
1175
|
-
__init10() {this._restoring = false}
|
|
1176
|
-
|
|
1177
|
-
// Bounded by `maxSubscribedStreams`; static records live apart so eviction
|
|
1178
|
-
// never lets a resolution re-lane them.
|
|
1179
|
-
|
|
1180
|
-
__init11() {this._static_subscriptions = /* @__PURE__ */ new Map()}
|
|
1181
|
-
__init12() {this._patterns = new (0, _chunkPRDX3HP6cjs.LruMap)(PATTERN_CACHE_SIZE)}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1000
|
+
// src/internal/defer-timer.ts
|
|
1001
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1002
|
+
var DeferTimer = (_class2 = class {
|
|
1003
|
+
__init2() {this._due = /* @__PURE__ */ new Map()}
|
|
1185
1004
|
|
|
1186
1005
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
max_subscribed_streams,
|
|
1194
|
-
declared_lanes,
|
|
1195
|
-
shard,
|
|
1196
|
-
on_init
|
|
1197
|
-
}) {;_class3.prototype.__init3.call(this);_class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this);_class3.prototype.__init6.call(this);_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this);_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);_class3.prototype.__init11.call(this);_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);
|
|
1198
|
-
this._key = shard ? `${registry_key(registry.events)}:${[...shard].sort().join(",")}` : registry_key(registry.events);
|
|
1199
|
-
this._dynamic_subscriptions = new (0, _chunkPRDX3HP6cjs.LruMap)(max_subscribed_streams);
|
|
1200
|
-
this._registry = registry;
|
|
1201
|
-
this._declared_lanes = declared_lanes;
|
|
1202
|
-
this._static_targets = static_targets;
|
|
1203
|
-
this._cd = cd;
|
|
1204
|
-
this._on_init = on_init;
|
|
1205
|
-
}
|
|
1206
|
-
get checkpoint() {
|
|
1207
|
-
return this._checkpoint;
|
|
1006
|
+
/**
|
|
1007
|
+
* @param on_wake - invoked once each time the earliest due-time elapses.
|
|
1008
|
+
* The consumer re-schedules for whatever is still parked.
|
|
1009
|
+
*/
|
|
1010
|
+
constructor(on_wake) {;_class2.prototype.__init2.call(this);
|
|
1011
|
+
this._on_wake = on_wake;
|
|
1208
1012
|
}
|
|
1209
|
-
/**
|
|
1210
|
-
|
|
1211
|
-
this.
|
|
1013
|
+
/** Number of currently parked streams. */
|
|
1014
|
+
get size() {
|
|
1015
|
+
return this._due.size;
|
|
1212
1016
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1017
|
+
/**
|
|
1018
|
+
* Park `stream` for a re-visit at `at` (ms since epoch). A plain
|
|
1019
|
+
* overwrite: the caller computes the authoritative next-visit for the
|
|
1020
|
+
* stream (the drain's `handle` already reconciles a stream's reactions
|
|
1021
|
+
* into one result per cycle), so there is no stale value to merge against.
|
|
1022
|
+
*/
|
|
1023
|
+
set(stream, at) {
|
|
1024
|
+
this._due.set(stream, at);
|
|
1219
1025
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
]);
|
|
1224
|
-
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - COLD_START_BACK_SCAN);
|
|
1225
|
-
for (const { stream, priority = 0, lane } of this._static_targets) {
|
|
1226
|
-
this._static_subscriptions.set(stream, {
|
|
1227
|
-
priority,
|
|
1228
|
-
lane
|
|
1229
|
-
});
|
|
1230
|
-
}
|
|
1231
|
-
await _optionalChain([this, 'access', _59 => _59._on_init, 'optionalCall', _60 => _60()]);
|
|
1026
|
+
/** Drop `stream` from the parked set (e.g. on a successful ack or block). */
|
|
1027
|
+
delete(stream) {
|
|
1028
|
+
this._due.delete(stream);
|
|
1232
1029
|
}
|
|
1233
1030
|
/**
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1031
|
+
* Drop every entry due at or before `before`. The drain calls it when a
|
|
1032
|
+
* pass that started at `before` claimed nothing: whatever was due by then
|
|
1033
|
+
* was handled elsewhere (another worker) or has no work left, so waking
|
|
1034
|
+
* for it again would spin.
|
|
1236
1035
|
*/
|
|
1237
|
-
|
|
1238
|
-
this.
|
|
1239
|
-
|
|
1240
|
-
await Promise.allSettled(this._passes);
|
|
1241
|
-
await restore();
|
|
1242
|
-
} finally {
|
|
1243
|
-
this._restoring = false;
|
|
1244
|
-
}
|
|
1245
|
-
this._init_promise = void 0;
|
|
1246
|
-
this._checkpoint = -1;
|
|
1247
|
-
this._dynamic_subscriptions.clear();
|
|
1248
|
-
this._static_subscriptions.clear();
|
|
1249
|
-
}
|
|
1250
|
-
/** Forget dynamic targets whose rows a full close deleted, so they re-subscribe. */
|
|
1251
|
-
forget_subscribed(streams) {
|
|
1252
|
-
for (const stream of streams) this._dynamic_subscriptions.delete(stream);
|
|
1036
|
+
prune(before) {
|
|
1037
|
+
for (const [stream, at] of this._due)
|
|
1038
|
+
if (at <= before) this._due.delete(stream);
|
|
1253
1039
|
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1040
|
+
/**
|
|
1041
|
+
* (Re)schedule the wake timer at the earliest pending due-time. Idempotent
|
|
1042
|
+
* — collapses many parked streams into a single timer. A no-op clears any
|
|
1043
|
+
* pending timer when the map is empty.
|
|
1044
|
+
*
|
|
1045
|
+
* The timer is `unref()`-ed so pending re-visits never keep the process
|
|
1046
|
+
* alive on their own.
|
|
1047
|
+
*/
|
|
1048
|
+
schedule() {
|
|
1049
|
+
if (this._timer) clearTimeout(this._timer);
|
|
1050
|
+
if (this._due.size === 0) {
|
|
1051
|
+
this._timer = void 0;
|
|
1052
|
+
return;
|
|
1262
1053
|
}
|
|
1263
|
-
|
|
1054
|
+
let earliest = Number.POSITIVE_INFINITY;
|
|
1055
|
+
for (const t of this._due.values()) if (t < earliest) earliest = t;
|
|
1056
|
+
const delay = Math.min(
|
|
1057
|
+
Math.max(0, earliest - Date.now()),
|
|
1058
|
+
MAX_TIMER_DELAY_MS
|
|
1059
|
+
);
|
|
1060
|
+
this._timer = setTimeout(() => {
|
|
1061
|
+
this._timer = void 0;
|
|
1062
|
+
this._on_wake();
|
|
1063
|
+
}, delay);
|
|
1064
|
+
this._timer.unref();
|
|
1264
1065
|
}
|
|
1265
|
-
/**
|
|
1266
|
-
|
|
1267
|
-
if (this.
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
try {
|
|
1271
|
-
return await pass;
|
|
1272
|
-
} finally {
|
|
1273
|
-
this._passes.delete(pass);
|
|
1066
|
+
/** Cancel any pending wake timer. Idempotent. Leaves the parked set intact. */
|
|
1067
|
+
stop() {
|
|
1068
|
+
if (this._timer) {
|
|
1069
|
+
clearTimeout(this._timer);
|
|
1070
|
+
this._timer = void 0;
|
|
1274
1071
|
}
|
|
1275
1072
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
if (lease
|
|
1287
|
-
|
|
1288
|
-
key: this._key,
|
|
1289
|
-
by: this._by,
|
|
1290
|
-
millis: CORRELATION_LEASE_MS
|
|
1291
|
-
});
|
|
1292
|
-
if (this._epoch !== epoch) return idle();
|
|
1293
|
-
this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
|
|
1294
|
-
if (correlating === false) return idle();
|
|
1295
|
-
}
|
|
1296
|
-
const after = this._checkpoint;
|
|
1297
|
-
const correlated = /* @__PURE__ */ new Map();
|
|
1298
|
-
let last_id = after;
|
|
1299
|
-
let stopped = false;
|
|
1300
|
-
const found = await _chunkPRDX3HP6cjs.store.call(void 0, ).query(
|
|
1301
|
-
(event) => {
|
|
1302
|
-
if (stopped) return;
|
|
1303
|
-
const register = this._registry.events[event.name];
|
|
1304
|
-
if (register) {
|
|
1305
|
-
for (const reaction of register.reactions.values()) {
|
|
1306
|
-
let resolved;
|
|
1307
|
-
try {
|
|
1308
|
-
resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
1309
|
-
} catch (error) {
|
|
1310
|
-
stopped = true;
|
|
1311
|
-
report_once(
|
|
1312
|
-
this._reported,
|
|
1313
|
-
`resolver|${reaction.handler.name}|${event.id}`,
|
|
1314
|
-
`Resolver of reaction "${reaction.handler.name}" threw on ${String(event.name)} #${event.id} (stream "${event.stream}"): ${String(error)}. Correlation stops before this event until the resolver stops throwing; work already found keeps draining.`
|
|
1315
|
-
);
|
|
1316
|
-
return;
|
|
1317
|
-
}
|
|
1318
|
-
if (!resolved) continue;
|
|
1319
|
-
let lane = resolved.lane;
|
|
1320
|
-
if (lane !== void 0 && !this._declared_lanes.has(lane)) {
|
|
1321
|
-
report_undeclared_lane(
|
|
1322
|
-
this._reported,
|
|
1323
|
-
reaction.handler.name,
|
|
1324
|
-
resolved.target,
|
|
1325
|
-
lane,
|
|
1326
|
-
this._declared_lanes
|
|
1327
|
-
);
|
|
1328
|
-
lane = void 0;
|
|
1329
|
-
}
|
|
1330
|
-
const fixed = this._static_subscriptions.get(resolved.target);
|
|
1331
|
-
const recorded = _nullishCoalesce(fixed, () => ( this._dynamic_subscriptions.get(resolved.target)));
|
|
1332
|
-
const priority = _nullishCoalesce(resolved.priority, () => ( 0));
|
|
1333
|
-
const upgraded = !recorded || !fixed && priority > recorded.priority;
|
|
1334
|
-
const carried = upgraded ? { priority, lane } : { priority: recorded.priority, lane: recorded.lane };
|
|
1335
|
-
const entry = correlated.get(resolved.target) || {
|
|
1336
|
-
source: resolved.source,
|
|
1337
|
-
priority: carried.priority,
|
|
1338
|
-
lane: carried.lane,
|
|
1339
|
-
upgraded,
|
|
1340
|
-
missed: !recorded,
|
|
1341
|
-
handler: reaction.handler.name,
|
|
1342
|
-
correlated_at: void 0
|
|
1343
|
-
};
|
|
1344
|
-
const seen_in_scan = correlated.has(resolved.target);
|
|
1345
|
-
const held_lane = _nullishCoalesce((seen_in_scan ? entry.lane : _optionalChain([recorded, 'optionalAccess', _61 => _61.lane])), () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
|
|
1346
|
-
const held_priority = seen_in_scan ? entry.priority : _optionalChain([recorded, 'optionalAccess', _62 => _62.priority]);
|
|
1347
|
-
const resolved_lane = _nullishCoalesce(lane, () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
|
|
1348
|
-
if (held_priority === priority && held_lane !== resolved_lane)
|
|
1349
|
-
report_lane_conflict(
|
|
1350
|
-
this._reported,
|
|
1351
|
-
reaction.handler.name,
|
|
1352
|
-
resolved.target,
|
|
1353
|
-
held_lane,
|
|
1354
|
-
resolved_lane
|
|
1355
|
-
);
|
|
1356
|
-
if (carried.priority > entry.priority) {
|
|
1357
|
-
entry.priority = carried.priority;
|
|
1358
|
-
entry.lane = carried.lane;
|
|
1359
|
-
entry.upgraded = upgraded;
|
|
1360
|
-
entry.handler = reaction.handler.name;
|
|
1361
|
-
}
|
|
1362
|
-
if (this._in_fetch_window(resolved.source, event.stream))
|
|
1363
|
-
entry.correlated_at = event.id;
|
|
1364
|
-
correlated.set(resolved.target, entry);
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
last_id = event.id;
|
|
1368
|
-
},
|
|
1369
|
-
// Resolvers see `pii: null`: correlate runs actor-less, and one
|
|
1370
|
-
// undecryptable row would otherwise stop every stream's reactions.
|
|
1371
|
-
{ after, limit, with_pii: false }
|
|
1372
|
-
);
|
|
1373
|
-
if (this._declared_lanes.size > 1) await this._recall(correlated);
|
|
1374
|
-
const read = last_id > after;
|
|
1375
|
-
if (this._epoch !== epoch) return idle();
|
|
1376
|
-
const streams = [];
|
|
1377
|
-
for (const [stream, entry] of correlated) {
|
|
1378
|
-
if (entry.upgraded || entry.correlated_at !== void 0)
|
|
1379
|
-
streams.push({
|
|
1380
|
-
stream,
|
|
1381
|
-
source: entry.source,
|
|
1382
|
-
priority: entry.priority,
|
|
1383
|
-
lane: entry.lane,
|
|
1384
|
-
correlated_at: entry.correlated_at
|
|
1385
|
-
});
|
|
1386
|
-
}
|
|
1387
|
-
if (streams.length) {
|
|
1388
|
-
const renewed_at = Date.now();
|
|
1389
|
-
const { subscribed, correlating } = await this._cd.subscribe(
|
|
1390
|
-
streams,
|
|
1391
|
-
last_id,
|
|
1392
|
-
lease ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
|
|
1393
|
-
);
|
|
1394
|
-
if (lease && correlating !== false)
|
|
1395
|
-
this._lease_until = renewed_at + CORRELATION_LEASE_MS;
|
|
1396
|
-
const marked = streams.filter(
|
|
1397
|
-
(entry) => entry.correlated_at !== void 0
|
|
1398
|
-
).length;
|
|
1399
|
-
this._checkpoint = last_id;
|
|
1400
|
-
for (const { stream, priority, lane } of streams) {
|
|
1401
|
-
if (_optionalChain([correlated, 'access', _63 => _63.get, 'call', _64 => _64(stream), 'optionalAccess', _65 => _65.upgraded]))
|
|
1402
|
-
this._dynamic_subscriptions.set(stream, {
|
|
1403
|
-
priority,
|
|
1404
|
-
lane
|
|
1405
|
-
});
|
|
1406
|
-
}
|
|
1407
|
-
return { kind: "scanned", last_id, subscribed, marked, read };
|
|
1408
|
-
}
|
|
1409
|
-
this._checkpoint = last_id;
|
|
1410
|
-
if (!stopped && found !== limit) this._lowered = raised;
|
|
1411
|
-
return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
|
|
1073
|
+
}, _class2);
|
|
1074
|
+
|
|
1075
|
+
// src/internal/drain-ratio.ts
|
|
1076
|
+
var RATIO_MIN = 0.2;
|
|
1077
|
+
var RATIO_MAX = 0.8;
|
|
1078
|
+
var RATIO_DEFAULT = 0.5;
|
|
1079
|
+
function compute_lag_lead_ratio(handled, lagging, leading) {
|
|
1080
|
+
let lagging_handled = 0;
|
|
1081
|
+
let leading_handled = 0;
|
|
1082
|
+
for (const { lease, handled: count } of handled) {
|
|
1083
|
+
if (lease.lagging) lagging_handled += count;
|
|
1084
|
+
else leading_handled += count;
|
|
1412
1085
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
);
|
|
1427
|
-
if (!row) return;
|
|
1428
|
-
this._dynamic_subscriptions.set(stream, {
|
|
1429
|
-
priority: row.priority,
|
|
1430
|
-
lane: row.lane
|
|
1431
|
-
});
|
|
1432
|
-
if (entry.priority > row.priority) return;
|
|
1433
|
-
const held_lane = _nullishCoalesce(row.lane, () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
|
|
1434
|
-
const resolved_lane = _nullishCoalesce(entry.lane, () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
|
|
1435
|
-
if (entry.priority === row.priority && held_lane !== resolved_lane)
|
|
1436
|
-
report_lane_conflict(
|
|
1437
|
-
this._reported,
|
|
1438
|
-
entry.handler,
|
|
1439
|
-
stream,
|
|
1440
|
-
held_lane,
|
|
1441
|
-
resolved_lane
|
|
1442
|
-
);
|
|
1443
|
-
entry.priority = row.priority;
|
|
1444
|
-
entry.lane = row.lane;
|
|
1445
|
-
entry.upgraded = false;
|
|
1446
|
-
})
|
|
1447
|
-
);
|
|
1448
|
-
}
|
|
1449
|
-
/** Release the lease early by re-acquiring it for zero ms. Best-effort. */
|
|
1450
|
-
async release_correlation() {
|
|
1451
|
-
try {
|
|
1452
|
-
this._lease_until = 0;
|
|
1453
|
-
this._epoch++;
|
|
1454
|
-
await this._cd.subscribe([], void 0, {
|
|
1455
|
-
key: this._key,
|
|
1456
|
-
by: this._by,
|
|
1457
|
-
millis: 0
|
|
1458
|
-
});
|
|
1459
|
-
} catch (error) {
|
|
1460
|
-
_chunkPRDX3HP6cjs.log.call(void 0, ).warn(
|
|
1461
|
-
`Could not hand back the correlation lease during shutdown; it expires on its own within ${CORRELATION_LEASE_MS}ms and correlation resumes normally after that. On a single-writer store this usually means another connection holds the database. Cause: ${String(_nullishCoalesce(error.cause, () => ( error)))}`
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
}, _class3);
|
|
1086
|
+
const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;
|
|
1087
|
+
const leading_avg = leading > 0 ? leading_handled / leading : 0;
|
|
1088
|
+
const total = lagging_avg + leading_avg;
|
|
1089
|
+
if (total === 0) return RATIO_DEFAULT;
|
|
1090
|
+
return Math.max(RATIO_MIN, Math.min(RATIO_MAX, lagging_avg / total));
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// src/internal/report-once.ts
|
|
1094
|
+
function report_once(seen, key, message) {
|
|
1095
|
+
if (seen.has(key)) return;
|
|
1096
|
+
seen.add(key);
|
|
1097
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).error(new Error(message));
|
|
1098
|
+
}
|
|
1466
1099
|
|
|
1467
1100
|
// src/internal/correlation-id.ts
|
|
1468
1101
|
|
|
@@ -1488,136 +1121,15 @@ function close_correlation(correlator, actor) {
|
|
|
1488
1121
|
});
|
|
1489
1122
|
}
|
|
1490
1123
|
|
|
1491
|
-
// src/internal/drain-cycle.ts
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
// src/internal/backoff.ts
|
|
1495
|
-
function compute_backoff_delay(retry, opts) {
|
|
1496
|
-
if (!opts || opts.baseMs <= 0) return 0;
|
|
1497
|
-
const r = Math.max(0, retry);
|
|
1498
|
-
let delay;
|
|
1499
|
-
switch (opts.strategy) {
|
|
1500
|
-
case "fixed":
|
|
1501
|
-
delay = opts.baseMs;
|
|
1502
|
-
break;
|
|
1503
|
-
case "linear":
|
|
1504
|
-
delay = opts.baseMs * (r + 1);
|
|
1505
|
-
break;
|
|
1506
|
-
case "exponential":
|
|
1507
|
-
delay = opts.baseMs * 2 ** r;
|
|
1508
|
-
if (opts.maxMs !== void 0) delay = Math.min(delay, opts.maxMs);
|
|
1509
|
-
break;
|
|
1510
|
-
default: {
|
|
1511
|
-
const _never = opts.strategy;
|
|
1512
|
-
throw new Error(`unknown backoff strategy: ${String(_never)}`);
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
if (opts.jitter) delay = delay * (0.5 + Math.random());
|
|
1516
|
-
return Math.max(0, Math.floor(delay));
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
// src/internal/defer-timer.ts
|
|
1520
|
-
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1521
|
-
var DeferTimer = (_class4 = class {
|
|
1522
|
-
__init14() {this._due = /* @__PURE__ */ new Map()}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
/**
|
|
1526
|
-
* @param on_wake - invoked once each time the earliest due-time elapses.
|
|
1527
|
-
* The consumer re-schedules for whatever is still parked.
|
|
1528
|
-
*/
|
|
1529
|
-
constructor(on_wake) {;_class4.prototype.__init14.call(this);
|
|
1530
|
-
this._on_wake = on_wake;
|
|
1531
|
-
}
|
|
1532
|
-
/** Number of currently parked streams. */
|
|
1533
|
-
get size() {
|
|
1534
|
-
return this._due.size;
|
|
1535
|
-
}
|
|
1536
|
-
/**
|
|
1537
|
-
* Park `stream` for a re-visit at `at` (ms since epoch). A plain
|
|
1538
|
-
* overwrite: the caller computes the authoritative next-visit for the
|
|
1539
|
-
* stream (the drain's `handle` already reconciles a stream's reactions
|
|
1540
|
-
* into one result per cycle), so there is no stale value to merge against.
|
|
1541
|
-
*/
|
|
1542
|
-
set(stream, at) {
|
|
1543
|
-
this._due.set(stream, at);
|
|
1544
|
-
}
|
|
1545
|
-
/** Drop `stream` from the parked set (e.g. on a successful ack or block). */
|
|
1546
|
-
delete(stream) {
|
|
1547
|
-
this._due.delete(stream);
|
|
1548
|
-
}
|
|
1549
|
-
/**
|
|
1550
|
-
* Drop every entry due at or before `before`. The drain calls it when a
|
|
1551
|
-
* pass that started at `before` claimed nothing: whatever was due by then
|
|
1552
|
-
* was handled elsewhere (another worker) or has no work left, so waking
|
|
1553
|
-
* for it again would spin.
|
|
1554
|
-
*/
|
|
1555
|
-
prune(before) {
|
|
1556
|
-
for (const [stream, at] of this._due)
|
|
1557
|
-
if (at <= before) this._due.delete(stream);
|
|
1558
|
-
}
|
|
1559
|
-
/**
|
|
1560
|
-
* (Re)schedule the wake timer at the earliest pending due-time. Idempotent
|
|
1561
|
-
* — collapses many parked streams into a single timer. A no-op clears any
|
|
1562
|
-
* pending timer when the map is empty.
|
|
1563
|
-
*
|
|
1564
|
-
* The timer is `unref()`-ed so pending re-visits never keep the process
|
|
1565
|
-
* alive on their own.
|
|
1566
|
-
*/
|
|
1567
|
-
schedule() {
|
|
1568
|
-
if (this._timer) clearTimeout(this._timer);
|
|
1569
|
-
if (this._due.size === 0) {
|
|
1570
|
-
this._timer = void 0;
|
|
1571
|
-
return;
|
|
1572
|
-
}
|
|
1573
|
-
let earliest = Number.POSITIVE_INFINITY;
|
|
1574
|
-
for (const t of this._due.values()) if (t < earliest) earliest = t;
|
|
1575
|
-
const delay = Math.min(
|
|
1576
|
-
Math.max(0, earliest - Date.now()),
|
|
1577
|
-
MAX_TIMER_DELAY_MS
|
|
1578
|
-
);
|
|
1579
|
-
this._timer = setTimeout(() => {
|
|
1580
|
-
this._timer = void 0;
|
|
1581
|
-
this._on_wake();
|
|
1582
|
-
}, delay);
|
|
1583
|
-
this._timer.unref();
|
|
1584
|
-
}
|
|
1585
|
-
/** Cancel any pending wake timer. Idempotent. Leaves the parked set intact. */
|
|
1586
|
-
stop() {
|
|
1587
|
-
if (this._timer) {
|
|
1588
|
-
clearTimeout(this._timer);
|
|
1589
|
-
this._timer = void 0;
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
}, _class4);
|
|
1593
|
-
|
|
1594
|
-
// src/internal/drain-ratio.ts
|
|
1595
|
-
var RATIO_MIN = 0.2;
|
|
1596
|
-
var RATIO_MAX = 0.8;
|
|
1597
|
-
var RATIO_DEFAULT = 0.5;
|
|
1598
|
-
function compute_lag_lead_ratio(handled, lagging, leading) {
|
|
1599
|
-
let lagging_handled = 0;
|
|
1600
|
-
let leading_handled = 0;
|
|
1601
|
-
for (const { lease, handled: count } of handled) {
|
|
1602
|
-
if (lease.lagging) lagging_handled += count;
|
|
1603
|
-
else leading_handled += count;
|
|
1604
|
-
}
|
|
1605
|
-
const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;
|
|
1606
|
-
const leading_avg = leading > 0 ? leading_handled / leading : 0;
|
|
1607
|
-
const total = lagging_avg + leading_avg;
|
|
1608
|
-
if (total === 0) return RATIO_DEFAULT;
|
|
1609
|
-
return Math.max(RATIO_MIN, Math.min(RATIO_MAX, lagging_avg / total));
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
1124
|
// src/internal/drain-ops.ts
|
|
1613
|
-
var claim = (lagging, leading, by, millis, lane) =>
|
|
1125
|
+
var claim = (lagging, leading, by, millis, lane) => _chunk4UWU5FANcjs.store.call(void 0, ).claim(lagging, leading, by, millis, lane);
|
|
1614
1126
|
async function fetch(leased, eventLimit) {
|
|
1615
1127
|
return Promise.all(
|
|
1616
1128
|
leased.map(async ({ stream, source, at, lagging }) => {
|
|
1617
1129
|
const events = [];
|
|
1618
|
-
const stream_exact = source !== void 0 &&
|
|
1130
|
+
const stream_exact = source !== void 0 && _chunk4UWU5FANcjs.is_literal_source.call(void 0, source, stream) ? true : void 0;
|
|
1619
1131
|
try {
|
|
1620
|
-
await
|
|
1132
|
+
await _chunk4UWU5FANcjs.store.call(void 0, ).query((e) => events.push(e), {
|
|
1621
1133
|
stream: source,
|
|
1622
1134
|
stream_exact,
|
|
1623
1135
|
after: at,
|
|
@@ -1630,23 +1142,23 @@ async function fetch(leased, eventLimit) {
|
|
|
1630
1142
|
at,
|
|
1631
1143
|
lagging,
|
|
1632
1144
|
events: [],
|
|
1633
|
-
error: _nullishCoalesce(_optionalChain([error, 'optionalAccess',
|
|
1145
|
+
error: _nullishCoalesce(_optionalChain([error, 'optionalAccess', _51 => _51.message]), () => ( String(error)))
|
|
1634
1146
|
};
|
|
1635
1147
|
}
|
|
1636
1148
|
return { stream, source, at, lagging, events };
|
|
1637
1149
|
})
|
|
1638
1150
|
);
|
|
1639
1151
|
}
|
|
1640
|
-
var ack = (leases) =>
|
|
1641
|
-
var block = (leases) =>
|
|
1642
|
-
var subscribe = (streams, correlated_at, correlator) =>
|
|
1152
|
+
var ack = (leases) => _chunk4UWU5FANcjs.store.call(void 0, ).ack(leases);
|
|
1153
|
+
var block = (leases) => _chunk4UWU5FANcjs.store.call(void 0, ).block(leases);
|
|
1154
|
+
var subscribe = (streams, correlated_at, correlator) => _chunk4UWU5FANcjs.store.call(void 0, ).subscribe(streams, correlated_at, correlator);
|
|
1643
1155
|
|
|
1644
1156
|
// src/internal/event-sourcing.ts
|
|
1645
1157
|
var _actpatch = require('@rotorsoft/act-patch');
|
|
1646
|
-
|
|
1158
|
+
|
|
1647
1159
|
var bare_patch = (_me, state2, partial) => _actpatch.patch.call(void 0, state2, partial);
|
|
1648
1160
|
var value_at = (value, path) => path.reduce(
|
|
1649
|
-
(at, key) => _optionalChain([at, 'optionalAccess',
|
|
1161
|
+
(at, key) => _optionalChain([at, 'optionalAccess', _52 => _52[key]]),
|
|
1650
1162
|
value
|
|
1651
1163
|
);
|
|
1652
1164
|
var check_invariants = (target, state2, schema, pii_aware) => {
|
|
@@ -1654,29 +1166,29 @@ var check_invariants = (target, state2, schema, pii_aware) => {
|
|
|
1654
1166
|
try {
|
|
1655
1167
|
result = schema.safeParse(state2);
|
|
1656
1168
|
} catch (error) {
|
|
1657
|
-
throw new (0,
|
|
1169
|
+
throw new (0, _chunkBCA423WPcjs.ValidationError)(target, state2, error);
|
|
1658
1170
|
}
|
|
1659
1171
|
if (result.success) return;
|
|
1660
1172
|
const issues = pii_aware ? result.error.issues.filter((issue) => {
|
|
1661
1173
|
const value = value_at(state2, issue.path);
|
|
1662
|
-
return value !==
|
|
1174
|
+
return value !== _chunkBCA423WPcjs.REDACTED && value !== _chunkBCA423WPcjs.SHREDDED;
|
|
1663
1175
|
}) : result.error.issues;
|
|
1664
1176
|
if (issues.length)
|
|
1665
|
-
throw new (0,
|
|
1177
|
+
throw new (0, _chunkBCA423WPcjs.ValidationError)(
|
|
1666
1178
|
target,
|
|
1667
1179
|
state2,
|
|
1668
1180
|
_zod.prettifyError.call(void 0, new (0, _zod.ZodError)(issues))
|
|
1669
1181
|
);
|
|
1670
1182
|
};
|
|
1671
1183
|
var DEFAULT_BATCH = 500;
|
|
1672
|
-
var cache_put = (stream, entry) =>
|
|
1673
|
-
(err) =>
|
|
1184
|
+
var cache_put = (stream, entry) => _chunk4UWU5FANcjs.cache.call(void 0, ).set(stream, entry).catch(
|
|
1185
|
+
(err) => _chunk4UWU5FANcjs.log.call(void 0, ).warn(
|
|
1674
1186
|
err,
|
|
1675
1187
|
"cache set skipped; the next load re-folds from the store"
|
|
1676
1188
|
)
|
|
1677
1189
|
);
|
|
1678
|
-
var cache_drop = (stream) =>
|
|
1679
|
-
(err) =>
|
|
1190
|
+
var cache_drop = (stream) => _chunk4UWU5FANcjs.cache.call(void 0, ).invalidate(stream).catch(
|
|
1191
|
+
(err) => _chunk4UWU5FANcjs.log.call(void 0, ).warn(
|
|
1680
1192
|
err,
|
|
1681
1193
|
"cache invalidate skipped; a stale checkpoint re-folds from its event_id"
|
|
1682
1194
|
)
|
|
@@ -1684,9 +1196,9 @@ var cache_drop = (stream) => _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(s
|
|
|
1684
1196
|
async function snap(snapshot) {
|
|
1685
1197
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
1686
1198
|
try {
|
|
1687
|
-
const [committed] = await
|
|
1199
|
+
const [committed] = await _chunk4UWU5FANcjs.store.call(void 0, ).commit(
|
|
1688
1200
|
stream,
|
|
1689
|
-
[{ name:
|
|
1201
|
+
[{ name: _chunkBCA423WPcjs.SNAP_EVENT, data: snapshot.state }],
|
|
1690
1202
|
{
|
|
1691
1203
|
correlation: meta.correlation,
|
|
1692
1204
|
causation: { event: { id, name, stream } }
|
|
@@ -1697,22 +1209,22 @@ async function snap(snapshot) {
|
|
|
1697
1209
|
return committed;
|
|
1698
1210
|
} catch (error) {
|
|
1699
1211
|
const reason = error instanceof Error ? error.message : String(error);
|
|
1700
|
-
|
|
1212
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).warn(
|
|
1701
1213
|
`Snapshot write failed on stream "${stream}": ${reason} \u2014 cold starts will replay full history until snapshots succeed.`
|
|
1702
1214
|
);
|
|
1703
1215
|
}
|
|
1704
1216
|
}
|
|
1705
1217
|
async function tombstone(stream, expectedVersion, correlation) {
|
|
1706
1218
|
try {
|
|
1707
|
-
const [committed] = await
|
|
1219
|
+
const [committed] = await _chunk4UWU5FANcjs.store.call(void 0, ).commit(
|
|
1708
1220
|
stream,
|
|
1709
|
-
[{ name:
|
|
1221
|
+
[{ name: _chunkBCA423WPcjs.TOMBSTONE_EVENT, data: {} }],
|
|
1710
1222
|
{ correlation, causation: {} },
|
|
1711
1223
|
expectedVersion
|
|
1712
1224
|
);
|
|
1713
1225
|
return committed;
|
|
1714
1226
|
} catch (error) {
|
|
1715
|
-
if (error instanceof
|
|
1227
|
+
if (error instanceof _chunkBCA423WPcjs.ConcurrencyError) return void 0;
|
|
1716
1228
|
throw error;
|
|
1717
1229
|
}
|
|
1718
1230
|
}
|
|
@@ -1742,9 +1254,9 @@ async function scan(source, opts = {}, callback) {
|
|
|
1742
1254
|
if (drop_closed_streams) {
|
|
1743
1255
|
await source.query(
|
|
1744
1256
|
(e) => {
|
|
1745
|
-
if (e.name ===
|
|
1257
|
+
if (e.name === _chunkBCA423WPcjs.TOMBSTONE_EVENT) closed_streams.add(e.stream);
|
|
1746
1258
|
},
|
|
1747
|
-
{ names: [
|
|
1259
|
+
{ names: [_chunkBCA423WPcjs.TOMBSTONE_EVENT] }
|
|
1748
1260
|
);
|
|
1749
1261
|
}
|
|
1750
1262
|
let max_id;
|
|
@@ -1766,16 +1278,16 @@ async function scan(source, opts = {}, callback) {
|
|
|
1766
1278
|
if (!is_valid(event))
|
|
1767
1279
|
throw new Error(`Invalid event at index ${processed}`);
|
|
1768
1280
|
if (on_progress) on_progress({ processed, id: event.id, max_id });
|
|
1769
|
-
if (drop_snapshots && event.name ===
|
|
1281
|
+
if (drop_snapshots && event.name === _chunkBCA423WPcjs.SNAP_EVENT) {
|
|
1770
1282
|
dropped_snaps++;
|
|
1771
1283
|
return;
|
|
1772
1284
|
}
|
|
1773
|
-
if (closed_streams.has(event.stream) && event.name !==
|
|
1285
|
+
if (closed_streams.has(event.stream) && event.name !== _chunkBCA423WPcjs.TOMBSTONE_EVENT) {
|
|
1774
1286
|
dropped_closed++;
|
|
1775
1287
|
return;
|
|
1776
1288
|
}
|
|
1777
1289
|
let migrated = event;
|
|
1778
|
-
const migration = _optionalChain([event_migrations, 'optionalAccess',
|
|
1290
|
+
const migration = _optionalChain([event_migrations, 'optionalAccess', _53 => _53[event.name]]);
|
|
1779
1291
|
if (migration) {
|
|
1780
1292
|
const old_data = migration.from_schema.parse(event.data);
|
|
1781
1293
|
const new_data = migration.migrate(old_data);
|
|
@@ -1797,7 +1309,7 @@ async function scan(source, opts = {}, callback) {
|
|
|
1797
1309
|
return;
|
|
1798
1310
|
}
|
|
1799
1311
|
let remapped = migrated;
|
|
1800
|
-
const caused_by = _optionalChain([migrated, 'access',
|
|
1312
|
+
const caused_by = _optionalChain([migrated, 'access', _54 => _54.meta, 'access', _55 => _55.causation, 'access', _56 => _56.event, 'optionalAccess', _57 => _57.id]);
|
|
1801
1313
|
if (caused_by !== void 0) {
|
|
1802
1314
|
const new_caused_by = id_map.get(caused_by);
|
|
1803
1315
|
if (new_caused_by !== void 0 && new_caused_by !== caused_by) {
|
|
@@ -1837,17 +1349,19 @@ async function scan(source, opts = {}, callback) {
|
|
|
1837
1349
|
async function load(me, target, callback, patch_fn = bare_patch) {
|
|
1838
1350
|
const { stream, actor, asOf } = target;
|
|
1839
1351
|
const time_travel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
|
|
1840
|
-
const
|
|
1352
|
+
const seeded = time_travel && asOf.limit === void 0 && !asOf.created_after;
|
|
1353
|
+
const cached = time_travel ? void 0 : await _chunk4UWU5FANcjs.cache.call(void 0, ).get(stream);
|
|
1841
1354
|
const cache_hit = !!cached;
|
|
1842
|
-
let state2 = _nullishCoalesce(_optionalChain([cached, 'optionalAccess',
|
|
1843
|
-
let patches = _nullishCoalesce(_optionalChain([cached, 'optionalAccess',
|
|
1844
|
-
let snaps = _nullishCoalesce(_optionalChain([cached, 'optionalAccess',
|
|
1355
|
+
let state2 = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _58 => _58.state]), () => ( (me.init ? me.init() : {})));
|
|
1356
|
+
let patches = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _59 => _59.patches]), () => ( 0));
|
|
1357
|
+
let snaps = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _60 => _60.snaps]), () => ( 0));
|
|
1845
1358
|
let replayed = 0;
|
|
1846
1359
|
let event;
|
|
1847
|
-
await
|
|
1360
|
+
await _chunk4UWU5FANcjs.store.call(void 0, ).query(
|
|
1848
1361
|
(raw) => {
|
|
1362
|
+
if (seeded && raw.name === _chunkBCA423WPcjs.SNAP_EVENT && replayed > 0) return;
|
|
1849
1363
|
event = me.view(raw, actor);
|
|
1850
|
-
if (event.name ===
|
|
1364
|
+
if (event.name === _chunkBCA423WPcjs.SNAP_EVENT) {
|
|
1851
1365
|
state2 = event.data;
|
|
1852
1366
|
snaps++;
|
|
1853
1367
|
patches = 0;
|
|
@@ -1856,12 +1370,12 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1856
1370
|
state2 = patch_fn(me, state2, me.patch[event.name](event, state2), event);
|
|
1857
1371
|
patches++;
|
|
1858
1372
|
replayed++;
|
|
1859
|
-
} else if (event.name !==
|
|
1860
|
-
|
|
1373
|
+
} else if (event.name !== _chunkBCA423WPcjs.TOMBSTONE_EVENT) {
|
|
1374
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).warn(
|
|
1861
1375
|
`Skipping unknown event "${String(event.name)}" on stream "${stream}" (id=${event.id}) \u2014 no reducer in state "${me.name}"`
|
|
1862
1376
|
);
|
|
1863
1377
|
}
|
|
1864
|
-
_optionalChain([callback, 'optionalCall',
|
|
1378
|
+
_optionalChain([callback, 'optionalCall', _61 => _61({
|
|
1865
1379
|
event,
|
|
1866
1380
|
state: state2,
|
|
1867
1381
|
version: event.version,
|
|
@@ -1878,10 +1392,14 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1878
1392
|
// `with_snaps` on every non-time-travel load: cold, it resumes from the
|
|
1879
1393
|
// latest snapshot; warm, it keeps a snapshot above a stale checkpoint,
|
|
1880
1394
|
// so a windowed close's prune can't fold the tail onto stale state.
|
|
1881
|
-
...cached ? { after: cached.event_id, with_snaps: true } :
|
|
1395
|
+
...cached ? { after: cached.event_id, with_snaps: true } : seeded ? (
|
|
1396
|
+
// From the start, past the resume floor, which could jump over the
|
|
1397
|
+
// time bound. The snapshots are for the seed.
|
|
1398
|
+
{ with_snaps: true, after: -1, ...asOf }
|
|
1399
|
+
) : time_travel ? asOf : { with_snaps: true }
|
|
1882
1400
|
}
|
|
1883
1401
|
);
|
|
1884
|
-
const head_is_tombstone = _optionalChain([event, 'optionalAccess',
|
|
1402
|
+
const head_is_tombstone = _optionalChain([event, 'optionalAccess', _62 => _62.name]) === _chunkBCA423WPcjs.TOMBSTONE_EVENT;
|
|
1885
1403
|
if (replayed > 0 && !time_travel && event && !me.pii_aware && !head_is_tombstone) {
|
|
1886
1404
|
await cache_put(stream, {
|
|
1887
1405
|
stream,
|
|
@@ -1895,9 +1413,9 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1895
1413
|
return {
|
|
1896
1414
|
event,
|
|
1897
1415
|
state: state2,
|
|
1898
|
-
version: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess',
|
|
1416
|
+
version: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _63 => _63.version]), () => ( _optionalChain([cached, 'optionalAccess', _64 => _64.version]))), () => ( -1)),
|
|
1899
1417
|
// Captured with `state`, so consumers never race a separate cache lookup.
|
|
1900
|
-
id: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess',
|
|
1418
|
+
id: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _65 => _65.id]), () => ( _optionalChain([cached, 'optionalAccess', _66 => _66.event_id]))), () => ( -1)),
|
|
1901
1419
|
patches,
|
|
1902
1420
|
snaps,
|
|
1903
1421
|
cache_hit,
|
|
@@ -1907,11 +1425,11 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1907
1425
|
async function action(me, action2, target, payload, options, patch_fn = bare_patch) {
|
|
1908
1426
|
const { stream, expectedVersion, actor } = target;
|
|
1909
1427
|
if (!stream) throw new Error("Missing target stream");
|
|
1910
|
-
const reactingTo = _optionalChain([options, 'optionalAccess',
|
|
1911
|
-
const correlator = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1912
|
-
const validated =
|
|
1913
|
-
const opts = _optionalChain([me, 'access',
|
|
1914
|
-
const max_retries = _nullishCoalesce(_optionalChain([opts, 'optionalAccess',
|
|
1428
|
+
const reactingTo = _optionalChain([options, 'optionalAccess', _67 => _67.reactingTo]);
|
|
1429
|
+
const correlator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _68 => _68.correlator]), () => ( default_correlator));
|
|
1430
|
+
const validated = _chunk4UWU5FANcjs.validate.call(void 0, action2, payload, me.actions[action2]);
|
|
1431
|
+
const opts = _optionalChain([me, 'access', _69 => _69.options, 'optionalAccess', _70 => _70[action2]]);
|
|
1432
|
+
const max_retries = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _71 => _71.maxRetries]), () => ( 0));
|
|
1915
1433
|
for (let attempt = 0; ; attempt++) {
|
|
1916
1434
|
try {
|
|
1917
1435
|
const snapshot = await load(
|
|
@@ -1920,21 +1438,21 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
|
|
|
1920
1438
|
void 0,
|
|
1921
1439
|
patch_fn
|
|
1922
1440
|
);
|
|
1923
|
-
if (_optionalChain([snapshot, 'access',
|
|
1924
|
-
throw new (0,
|
|
1441
|
+
if (_optionalChain([snapshot, 'access', _72 => _72.event, 'optionalAccess', _73 => _73.name]) === _chunkBCA423WPcjs.TOMBSTONE_EVENT)
|
|
1442
|
+
throw new (0, _chunkBCA423WPcjs.StreamClosedError)(stream);
|
|
1925
1443
|
const expected = _nullishCoalesce(expectedVersion, () => ( snapshot.version));
|
|
1926
|
-
for (const { valid, description } of _nullishCoalesce(_optionalChain([me, 'access',
|
|
1444
|
+
for (const { valid, description } of _nullishCoalesce(_optionalChain([me, 'access', _74 => _74.given, 'optionalAccess', _75 => _75[action2]]), () => ( [])))
|
|
1927
1445
|
if (!valid(snapshot.state, actor))
|
|
1928
|
-
throw new (0,
|
|
1446
|
+
throw new (0, _chunkBCA423WPcjs.InvariantError)(
|
|
1929
1447
|
action2,
|
|
1930
1448
|
validated,
|
|
1931
1449
|
target,
|
|
1932
1450
|
snapshot,
|
|
1933
1451
|
description
|
|
1934
1452
|
);
|
|
1935
|
-
for (const { holds, description } of _nullishCoalesce(_optionalChain([me, 'access',
|
|
1453
|
+
for (const { holds, description } of _nullishCoalesce(_optionalChain([me, 'access', _76 => _76.requires, 'optionalAccess', _77 => _77[action2]]), () => ( [])))
|
|
1936
1454
|
if (!holds(validated, snapshot.state, actor))
|
|
1937
|
-
throw new (0,
|
|
1455
|
+
throw new (0, _chunkBCA423WPcjs.PreconditionError)(
|
|
1938
1456
|
action2,
|
|
1939
1457
|
validated,
|
|
1940
1458
|
target,
|
|
@@ -1947,11 +1465,11 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
|
|
|
1947
1465
|
const tuples = Array.isArray(result[0]) ? result : [result];
|
|
1948
1466
|
const events = tuples.map(([name, data]) => ({
|
|
1949
1467
|
name,
|
|
1950
|
-
data:
|
|
1468
|
+
data: _chunk4UWU5FANcjs.validate.call(void 0, name, data, me.events[name])
|
|
1951
1469
|
}));
|
|
1952
1470
|
const emitted = events.map((e) => me.message(e));
|
|
1953
1471
|
const meta = {
|
|
1954
|
-
correlation: _optionalChain([reactingTo, 'optionalAccess',
|
|
1472
|
+
correlation: _optionalChain([reactingTo, 'optionalAccess', _78 => _78.meta, 'access', _79 => _79.correlation]) || correlator({
|
|
1955
1473
|
action: action2,
|
|
1956
1474
|
state: me.name,
|
|
1957
1475
|
stream,
|
|
@@ -1994,9 +1512,9 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
|
|
|
1994
1512
|
);
|
|
1995
1513
|
let committed;
|
|
1996
1514
|
try {
|
|
1997
|
-
committed = await
|
|
1515
|
+
committed = await _chunk4UWU5FANcjs.store.call(void 0, ).commit(stream, emitted, meta, expected);
|
|
1998
1516
|
} catch (error) {
|
|
1999
|
-
if (error instanceof
|
|
1517
|
+
if (error instanceof _chunkBCA423WPcjs.ConcurrencyError) void cache_drop(stream);
|
|
2000
1518
|
throw error;
|
|
2001
1519
|
}
|
|
2002
1520
|
const snapshots = committed.map((row, i) => ({
|
|
@@ -2011,31 +1529,31 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
|
|
|
2011
1529
|
replayed: snapshot.replayed
|
|
2012
1530
|
}));
|
|
2013
1531
|
const last = snapshots.at(-1);
|
|
2014
|
-
const snap_event = _optionalChain([me, 'access',
|
|
1532
|
+
const snap_event = _optionalChain([me, 'access', _80 => _80.snap, 'optionalCall', _81 => _81(last)]) ? await snap(last) : void 0;
|
|
2015
1533
|
if (!me.pii_aware)
|
|
2016
1534
|
void cache_put(stream, {
|
|
2017
1535
|
stream,
|
|
2018
1536
|
state: last.state,
|
|
2019
|
-
version: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess',
|
|
2020
|
-
event_id: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess',
|
|
1537
|
+
version: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _82 => _82.version]), () => ( last.event.version)),
|
|
1538
|
+
event_id: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _83 => _83.id]), () => ( last.event.id)),
|
|
2021
1539
|
patches: snap_event ? 0 : last.patches,
|
|
2022
1540
|
snaps: snap_event ? last.snaps + 1 : last.snaps
|
|
2023
1541
|
});
|
|
2024
1542
|
return snapshots;
|
|
2025
1543
|
} catch (error) {
|
|
2026
|
-
if (!(error instanceof
|
|
1544
|
+
if (!(error instanceof _chunkBCA423WPcjs.ConcurrencyError)) throw error;
|
|
2027
1545
|
if (expectedVersion !== void 0) throw error;
|
|
2028
1546
|
if (attempt >= max_retries) throw error;
|
|
2029
|
-
if (_optionalChain([opts, 'optionalAccess',
|
|
1547
|
+
if (_optionalChain([opts, 'optionalAccess', _84 => _84.backoff])) {
|
|
2030
1548
|
const delay_ms = compute_backoff_delay(attempt, opts.backoff);
|
|
2031
|
-
if (delay_ms > 0) await
|
|
1549
|
+
if (delay_ms > 0) await _chunk4UWU5FANcjs.sleep.call(void 0, delay_ms);
|
|
2032
1550
|
}
|
|
2033
1551
|
}
|
|
2034
1552
|
}
|
|
2035
1553
|
}
|
|
2036
1554
|
|
|
2037
1555
|
// src/internal/tracing.ts
|
|
2038
|
-
var PRETTY =
|
|
1556
|
+
var PRETTY = _chunk4UWU5FANcjs.config.call(void 0, ).env !== "production";
|
|
2039
1557
|
var C_BLUE = "\x1B[38;5;39m";
|
|
2040
1558
|
var C_ORANGE = "\x1B[38;5;208m";
|
|
2041
1559
|
var C_GREEN = "\x1B[38;5;42m";
|
|
@@ -2081,9 +1599,9 @@ var as_of_marker = (asOf) => {
|
|
|
2081
1599
|
return parts.length ? ` (as-of ${parts.join(" ")})` : " (as-of)";
|
|
2082
1600
|
};
|
|
2083
1601
|
var traced = (inner, exit, entry) => (async (...args) => {
|
|
2084
|
-
_optionalChain([entry, 'optionalCall',
|
|
1602
|
+
_optionalChain([entry, 'optionalCall', _85 => _85(...args)]);
|
|
2085
1603
|
const result = await inner(...args);
|
|
2086
|
-
_optionalChain([exit, 'optionalCall',
|
|
1604
|
+
_optionalChain([exit, 'optionalCall', _86 => _86(result, ...args)]);
|
|
2087
1605
|
return result;
|
|
2088
1606
|
});
|
|
2089
1607
|
function build_es(logger, correlator = default_correlator, patch_fn = bare_patch) {
|
|
@@ -2092,7 +1610,7 @@ function build_es(logger, correlator = default_correlator, patch_fn = bare_patch
|
|
|
2092
1610
|
action_name,
|
|
2093
1611
|
target,
|
|
2094
1612
|
payload,
|
|
2095
|
-
{ ...options, correlator: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1613
|
+
{ ...options, correlator: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.correlator]), () => ( correlator)) },
|
|
2096
1614
|
patch_fn
|
|
2097
1615
|
);
|
|
2098
1616
|
const bound_load = (me, target, callback) => load(me, target, callback, patch_fn);
|
|
@@ -2166,7 +1684,7 @@ function build_drain(logger) {
|
|
|
2166
1684
|
subscribe: logger.level !== "trace" ? subscribe : traced(subscribe, (result, streams) => {
|
|
2167
1685
|
if (!result.subscribed) return;
|
|
2168
1686
|
const lanes = new Set(streams.map((s) => _nullishCoalesce(s.lane, () => ( "default"))));
|
|
2169
|
-
const uniform_lane = lanes.size === 1 ? _optionalChain([streams, 'access',
|
|
1687
|
+
const uniform_lane = lanes.size === 1 ? _optionalChain([streams, 'access', _88 => _88[0], 'optionalAccess', _89 => _89.lane]) : void 0;
|
|
2170
1688
|
const data = streams.map(
|
|
2171
1689
|
({ stream, lane }) => uniform_lane || !lane || lane === "default" ? hue(C_STREAM, stream) : `${hue(C_STREAM, stream)}${dim(`[${lane}]`)}`
|
|
2172
1690
|
).join(" ");
|
|
@@ -2178,7 +1696,7 @@ function build_drain(logger) {
|
|
|
2178
1696
|
}
|
|
2179
1697
|
function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
2180
1698
|
if (logger.level !== "trace" || !leased.length) return;
|
|
2181
|
-
const lane = _optionalChain([leased, 'access',
|
|
1699
|
+
const lane = _optionalChain([leased, 'access', _90 => _90[0], 'optionalAccess', _91 => _91.lane]);
|
|
2182
1700
|
const fetch_by_stream = new Map(fetched.map((f) => [f.stream, f]));
|
|
2183
1701
|
const acked_by_stream = new Map(acked.map((a) => [a.stream, a.at]));
|
|
2184
1702
|
const blocked_by_stream = new Map(blocked.map((b) => [b.stream, b.error]));
|
|
@@ -2187,8 +1705,8 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
|
2187
1705
|
);
|
|
2188
1706
|
const detail = leased.map(({ stream, at, retry }) => {
|
|
2189
1707
|
const f = fetch_by_stream.get(stream);
|
|
2190
|
-
const key = _optionalChain([f, 'optionalAccess',
|
|
2191
|
-
const events = _optionalChain([f, 'optionalAccess',
|
|
1708
|
+
const key = _optionalChain([f, 'optionalAccess', _92 => _92.source]) ? `${hue(C_STREAM, stream)}${dim(`<-${f.source}`)}` : hue(C_STREAM, stream);
|
|
1709
|
+
const events = _optionalChain([f, 'optionalAccess', _93 => _93.events, 'access', _94 => _94.length]) ? ` ${dim(
|
|
2192
1710
|
`[${f.events.map(({ id, name }) => `#${id} ${String(name)}`).join(", ")}]`
|
|
2193
1711
|
)}` : "";
|
|
2194
1712
|
const acked_at = acked_by_stream.get(stream);
|
|
@@ -2201,326 +1719,1216 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
|
2201
1719
|
if (blocked_error !== void 0) {
|
|
2202
1720
|
fail_part = `${hue(C_ERR, `\u2717 @${failed_at}/${retry}`)} ${dim(`(${blocked_error})`)}`;
|
|
2203
1721
|
} else {
|
|
2204
|
-
fail_part = `${hue(C_MISS, `\u26A0 @${failed_at}/${retry}`)} ${dim(`(${failure.error})`)}`;
|
|
1722
|
+
fail_part = `${hue(C_MISS, `\u26A0 @${failed_at}/${retry}`)} ${dim(`(${failure.error})`)}`;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
let tail;
|
|
1726
|
+
if (ack_part && fail_part) tail = ` ${ack_part} ${fail_part}`;
|
|
1727
|
+
else if (ack_part) tail = ` ${ack_part}`;
|
|
1728
|
+
else if (fail_part) tail = ` ${fail_part}`;
|
|
1729
|
+
else tail = ` ${dim(`\u2298 @${at}/${retry}`)}`;
|
|
1730
|
+
return `${key}${events}${tail}`;
|
|
1731
|
+
}).join(", ");
|
|
1732
|
+
logger.trace(`${drain_caption("drained", lane)} ${detail}`);
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
// src/internal/drain-cycle.ts
|
|
1736
|
+
function budget_exhausted(lease, options, store_failing) {
|
|
1737
|
+
if (store_failing || !_optionalChain([options, 'optionalAccess', _95 => _95.blockOnError]) || lease.retry <= options.maxRetries)
|
|
1738
|
+
return void 0;
|
|
1739
|
+
const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress \u2014 the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. That means every attempt lost its lease before it could ack: move the reaction to a lane whose leaseMillis covers the handler, then unblock the stream.`;
|
|
1740
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).error(error);
|
|
1741
|
+
return { lease, handled: 0, acked_at: lease.at, error, block: true };
|
|
1742
|
+
}
|
|
1743
|
+
function fetch_failure_policy(registry) {
|
|
1744
|
+
let blockOnError = true;
|
|
1745
|
+
let maxRetries = 0;
|
|
1746
|
+
for (const register of Object.values(registry.events))
|
|
1747
|
+
for (const reaction of register.reactions.values()) {
|
|
1748
|
+
blockOnError &&= reaction.options.blockOnError;
|
|
1749
|
+
maxRetries = Math.max(maxRetries, reaction.options.maxRetries);
|
|
1750
|
+
}
|
|
1751
|
+
return { blockOnError, maxRetries };
|
|
1752
|
+
}
|
|
1753
|
+
function finalize(lease, handled, at, error, options, logger, failed_at) {
|
|
1754
|
+
if (!error) return { lease, handled, acked_at: at };
|
|
1755
|
+
logger.error(error);
|
|
1756
|
+
const non_retryable = error instanceof _chunkBCA423WPcjs.NonRetryableError;
|
|
1757
|
+
const block2 = options.blockOnError && (non_retryable || lease.retry >= options.maxRetries);
|
|
1758
|
+
if (block2)
|
|
1759
|
+
logger.error(
|
|
1760
|
+
non_retryable ? `Blocking ${lease.stream} on non-retryable error.` : `Blocking ${lease.stream} after ${lease.retry} retries.`
|
|
1761
|
+
);
|
|
1762
|
+
const next_attempt_at = block2 ? void 0 : Date.now() + compute_backoff_delay(lease.retry, _nullishCoalesce(options.backoff, () => ( _chunk4UWU5FANcjs.DEFAULT_BACKOFF)));
|
|
1763
|
+
return {
|
|
1764
|
+
lease,
|
|
1765
|
+
handled,
|
|
1766
|
+
acked_at: at,
|
|
1767
|
+
error: error.message,
|
|
1768
|
+
block: block2,
|
|
1769
|
+
next_attempt_at,
|
|
1770
|
+
failed_at
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function warn_misrouted(seen, stream, handler, event) {
|
|
1774
|
+
report_once(
|
|
1775
|
+
seen,
|
|
1776
|
+
`${stream}|${handler}|${event}`,
|
|
1777
|
+
`Reaction "${handler}" on "${event}" resolved to target "${stream}", which a projection already serves. A target is served by one batch handler or one state projection, so this reaction can never run \u2014 and delivering to it would hand the projection an aggregate from another stream. Skipping it. The equivalent static \`.to({ target })\` is rejected at build; a dynamic resolver's target is only knowable here.`
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
async function run_drain_cycle(deps, cycle) {
|
|
1781
|
+
const { ops, registry, batch_handlers, handle, handle_batch, lane } = deps;
|
|
1782
|
+
const {
|
|
1783
|
+
lagging,
|
|
1784
|
+
leading,
|
|
1785
|
+
eventLimit,
|
|
1786
|
+
leaseMillis,
|
|
1787
|
+
misrouted,
|
|
1788
|
+
store_failing
|
|
1789
|
+
} = cycle;
|
|
1790
|
+
const leased = await ops.claim(
|
|
1791
|
+
lagging,
|
|
1792
|
+
leading,
|
|
1793
|
+
_crypto.randomUUID.call(void 0, ),
|
|
1794
|
+
leaseMillis,
|
|
1795
|
+
lane
|
|
1796
|
+
);
|
|
1797
|
+
if (!leased.length) return void 0;
|
|
1798
|
+
const fetched = await ops.fetch(leased, eventLimit);
|
|
1799
|
+
const fetch_map = /* @__PURE__ */ new Map();
|
|
1800
|
+
const fetch_window_at = fetched.reduce(
|
|
1801
|
+
(max, { at, events }) => Math.max(max, _optionalChain([events, 'access', _96 => _96.at, 'call', _97 => _97(-1), 'optionalAccess', _98 => _98.id]) || at),
|
|
1802
|
+
0
|
|
1803
|
+
);
|
|
1804
|
+
for (const f of fetched) {
|
|
1805
|
+
const { stream, events } = f;
|
|
1806
|
+
let failed;
|
|
1807
|
+
const payloads = events.flatMap((event) => {
|
|
1808
|
+
const register = registry.events[event.name];
|
|
1809
|
+
if (!register) return [];
|
|
1810
|
+
return [...register.reactions.values()].filter((reaction) => {
|
|
1811
|
+
const resolver = reaction.resolver;
|
|
1812
|
+
const dynamic = typeof resolver === "function";
|
|
1813
|
+
let resolved;
|
|
1814
|
+
try {
|
|
1815
|
+
resolved = dynamic ? resolver(event) : resolver;
|
|
1816
|
+
} catch (error) {
|
|
1817
|
+
failed ??= {
|
|
1818
|
+
error: new Error(
|
|
1819
|
+
`Resolver of reaction "${reaction.handler.name}" threw on ${String(event.name)} #${event.id} (stream "${event.stream}"): ${String(error)}`
|
|
1820
|
+
),
|
|
1821
|
+
options: reaction.options
|
|
1822
|
+
};
|
|
1823
|
+
return false;
|
|
1824
|
+
}
|
|
1825
|
+
if (!resolved || resolved.target !== stream) return false;
|
|
1826
|
+
if (!dynamic || !batch_handlers.has(stream)) return true;
|
|
1827
|
+
warn_misrouted(
|
|
1828
|
+
misrouted,
|
|
1829
|
+
stream,
|
|
1830
|
+
reaction.handler.name,
|
|
1831
|
+
String(event.name)
|
|
1832
|
+
);
|
|
1833
|
+
return false;
|
|
1834
|
+
}).map((reaction) => ({ ...reaction, event }));
|
|
1835
|
+
});
|
|
1836
|
+
fetch_map.set(stream, { fetch: f, payloads, failed });
|
|
1837
|
+
}
|
|
1838
|
+
const handled = await Promise.all(
|
|
1839
|
+
leased.map((lease) => {
|
|
1840
|
+
const entry = fetch_map.get(lease.stream);
|
|
1841
|
+
if (entry.fetch.error !== void 0) {
|
|
1842
|
+
const policy = fetch_failure_policy(registry);
|
|
1843
|
+
return Promise.resolve(
|
|
1844
|
+
finalize(
|
|
1845
|
+
lease,
|
|
1846
|
+
0,
|
|
1847
|
+
lease.at,
|
|
1848
|
+
new Error(`Fetch failed for ${lease.stream}: ${entry.fetch.error}`),
|
|
1849
|
+
store_failing ? { ...policy, blockOnError: false } : policy,
|
|
1850
|
+
deps.logger
|
|
1851
|
+
)
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
if (entry.failed)
|
|
1855
|
+
return Promise.resolve(
|
|
1856
|
+
finalize(
|
|
1857
|
+
lease,
|
|
1858
|
+
0,
|
|
1859
|
+
lease.at,
|
|
1860
|
+
entry.failed.error,
|
|
1861
|
+
entry.failed.options,
|
|
1862
|
+
deps.logger
|
|
1863
|
+
)
|
|
1864
|
+
);
|
|
1865
|
+
const at = _optionalChain([entry, 'access', _99 => _99.fetch, 'access', _100 => _100.events, 'access', _101 => _101.at, 'call', _102 => _102(-1), 'optionalAccess', _103 => _103.id]) || fetch_window_at;
|
|
1866
|
+
const { payloads } = entry;
|
|
1867
|
+
const exhausted = budget_exhausted(
|
|
1868
|
+
lease,
|
|
1869
|
+
_optionalChain([payloads, 'access', _104 => _104[0], 'optionalAccess', _105 => _105.options]),
|
|
1870
|
+
store_failing
|
|
1871
|
+
);
|
|
1872
|
+
if (exhausted) return Promise.resolve(exhausted);
|
|
1873
|
+
const batchHandler = batch_handlers.get(lease.stream);
|
|
1874
|
+
if (batchHandler && payloads.length > 0) {
|
|
1875
|
+
return handle_batch({ ...lease, at }, payloads, batchHandler);
|
|
1876
|
+
}
|
|
1877
|
+
return handle({ ...lease, at }, payloads);
|
|
1878
|
+
})
|
|
1879
|
+
);
|
|
1880
|
+
const to_block = handled.filter(({ block: block2 }) => block2).map(({ lease, error }) => ({ ...lease, error }));
|
|
1881
|
+
const blocked = to_block.length ? await ops.block(to_block) : [];
|
|
1882
|
+
if (blocked.length) deps.on_blocked(blocked);
|
|
1883
|
+
const submitted = handled.flatMap((h, i) => {
|
|
1884
|
+
const advance = h.handled > 0 ? h.acked_at : leased[i].at;
|
|
1885
|
+
return h.defer !== void 0 ? { ...h.lease, at: advance, due: h.defer, retry: -1 } : h.next_attempt_at !== void 0 ? { ...h.lease, at: advance, due: h.next_attempt_at } : h.handled > 0 || !h.error ? { ...h.lease, at: h.acked_at } : [];
|
|
1886
|
+
});
|
|
1887
|
+
const acked = submitted.length ? await ops.ack(submitted) : [];
|
|
1888
|
+
const expected = submitted.filter((l) => l.due === void 0).length;
|
|
1889
|
+
if (acked.length < expected)
|
|
1890
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).warn(
|
|
1891
|
+
`drain: ${expected - acked.length} of ${expected} acks were dropped \u2014 the lease was taken by another worker mid-handler. That work will be redelivered (at-least-once), but persistent drops mean leaseMillis is too short for this handler.`
|
|
1892
|
+
);
|
|
1893
|
+
const closeable = handled.filter((h) => h.close !== void 0).map((h) => h.close);
|
|
1894
|
+
return { leased, fetched, handled, acked, blocked, closeable };
|
|
1895
|
+
}
|
|
1896
|
+
var EMPTY_DRAIN = {
|
|
1897
|
+
fetched: [],
|
|
1898
|
+
leased: [],
|
|
1899
|
+
acked: [],
|
|
1900
|
+
blocked: []
|
|
1901
|
+
};
|
|
1902
|
+
function merge_drains(drains) {
|
|
1903
|
+
return {
|
|
1904
|
+
fetched: drains.flatMap((d) => d.fetched),
|
|
1905
|
+
leased: drains.flatMap((d) => d.leased),
|
|
1906
|
+
acked: drains.flatMap((d) => d.acked),
|
|
1907
|
+
blocked: drains.flatMap((d) => d.blocked)
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
var RETRY = "";
|
|
1911
|
+
var DrainController = (_class3 = class {
|
|
1912
|
+
// Armed while `_raised` is ahead of `_lowered` (the raise count the last
|
|
1913
|
+
// empty claim saw), so a claim never lowers over a raise that landed
|
|
1914
|
+
// during it.
|
|
1915
|
+
__init3() {this._raised = 0}
|
|
1916
|
+
__init4() {this._lowered = 0}
|
|
1917
|
+
__init5() {this._ratio = 0.5}
|
|
1918
|
+
// Local wake at the earliest parked (backoff or defer) visit, or at the
|
|
1919
|
+
// lease expiry after a failed pass (the {@link RETRY} key); the schedule
|
|
1920
|
+
// itself is persisted. On an idle app nothing else would drain it. It
|
|
1921
|
+
// drains until a pass leases nothing or the controller stops, and an entry
|
|
1922
|
+
// stays until handled or until a later pass claims nothing.
|
|
1923
|
+
__init6() {this._defer = new DeferTimer(() => {
|
|
1924
|
+
this.arm();
|
|
1925
|
+
void this._deps.run_scoped(async () => {
|
|
1926
|
+
while ((await this.drain()).leased.length > 0) ;
|
|
1927
|
+
});
|
|
1928
|
+
})}
|
|
1929
|
+
|
|
1930
|
+
__init7() {this._misrouted = /* @__PURE__ */ new Set()}
|
|
1931
|
+
__init8() {this._stopped = false}
|
|
1932
|
+
// The pass in flight. Never rejects; graceful shutdown waits on it.
|
|
1933
|
+
|
|
1934
|
+
|
|
1935
|
+
constructor(deps) {;_class3.prototype.__init3.call(this);_class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this);_class3.prototype.__init6.call(this);_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this);
|
|
1936
|
+
this._deps = deps;
|
|
1937
|
+
}
|
|
1938
|
+
arm() {
|
|
1939
|
+
this._raised++;
|
|
1940
|
+
}
|
|
1941
|
+
/** Cold start: re-seed a persisted `deferred_at` into the local wake. */
|
|
1942
|
+
seed_defer(stream, at) {
|
|
1943
|
+
this._defer.set(stream, at);
|
|
1944
|
+
this._defer.schedule();
|
|
1945
|
+
}
|
|
1946
|
+
get armed() {
|
|
1947
|
+
return this._raised !== this._lowered;
|
|
1948
|
+
}
|
|
1949
|
+
get inflight() {
|
|
1950
|
+
return this._inflight;
|
|
1951
|
+
}
|
|
1952
|
+
/** This lane's configured lease, or `undefined`; the shutdown grace basis. */
|
|
1953
|
+
get lease_millis() {
|
|
1954
|
+
return _optionalChain([this, 'access', _106 => _106._deps, 'access', _107 => _107.defaults, 'optionalAccess', _108 => _108.leaseMillis]);
|
|
1955
|
+
}
|
|
1956
|
+
get lane() {
|
|
1957
|
+
return this._deps.lane;
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* Drains every `cycleMs` while armed; the unref'd timer never holds the
|
|
1961
|
+
* process. Called once, when the controller is built.
|
|
1962
|
+
*/
|
|
1963
|
+
start(cycleMs) {
|
|
1964
|
+
const run = this._deps.run_scoped;
|
|
1965
|
+
const tick = async () => {
|
|
1966
|
+
if (this.armed) await run(() => this.drain());
|
|
1967
|
+
if (this._stopped) return;
|
|
1968
|
+
this._worker = setTimeout(tick, cycleMs);
|
|
1969
|
+
this._worker.unref();
|
|
1970
|
+
};
|
|
1971
|
+
this._worker = setTimeout(tick, cycleMs);
|
|
1972
|
+
this._worker.unref();
|
|
1973
|
+
}
|
|
1974
|
+
stop() {
|
|
1975
|
+
this._stopped = true;
|
|
1976
|
+
if (this._worker) {
|
|
1977
|
+
clearTimeout(this._worker);
|
|
1978
|
+
this._worker = void 0;
|
|
1979
|
+
}
|
|
1980
|
+
this._defer.stop();
|
|
1981
|
+
}
|
|
1982
|
+
async drain(options = {}) {
|
|
1983
|
+
if (!this.armed || this._stopped || this._inflight)
|
|
1984
|
+
return EMPTY_DRAIN;
|
|
1985
|
+
const d = _nullishCoalesce(this._deps.defaults, () => ( {}));
|
|
1986
|
+
const streamLimit = _nullishCoalesce(_nullishCoalesce(d.streamLimit, () => ( options.streamLimit)), () => ( _chunk4UWU5FANcjs.DEFAULT_STREAM_LIMIT));
|
|
1987
|
+
const eventLimit = _nullishCoalesce(options.eventLimit, () => ( _chunk4UWU5FANcjs.DEFAULT_EVENT_LIMIT));
|
|
1988
|
+
const leaseMillis = _nullishCoalesce(_nullishCoalesce(d.leaseMillis, () => ( options.leaseMillis)), () => ( _chunk4UWU5FANcjs.DEFAULT_LEASE_MILLIS));
|
|
1989
|
+
if (this._deps.breaker.state(Date.now()) === "open")
|
|
1990
|
+
return EMPTY_DRAIN;
|
|
1991
|
+
const pass = this._pass(streamLimit, eventLimit, leaseMillis).finally(
|
|
1992
|
+
() => {
|
|
1993
|
+
this._inflight = void 0;
|
|
1994
|
+
}
|
|
1995
|
+
);
|
|
1996
|
+
this._inflight = pass;
|
|
1997
|
+
return pass;
|
|
1998
|
+
}
|
|
1999
|
+
// One claim → fetch → handle → ack pass. Never throws.
|
|
2000
|
+
async _pass(streamLimit, eventLimit, leaseMillis) {
|
|
2001
|
+
try {
|
|
2002
|
+
const lagging = Math.ceil(streamLimit * this._ratio);
|
|
2003
|
+
const leading = streamLimit - lagging;
|
|
2004
|
+
const started = Date.now();
|
|
2005
|
+
const raised = this._raised;
|
|
2006
|
+
const cycle = await run_drain_cycle(this._deps, {
|
|
2007
|
+
lagging,
|
|
2008
|
+
leading,
|
|
2009
|
+
eventLimit,
|
|
2010
|
+
leaseMillis,
|
|
2011
|
+
misrouted: this._misrouted,
|
|
2012
|
+
store_failing: this._deps.breaker.failing
|
|
2013
|
+
});
|
|
2014
|
+
if (!cycle) {
|
|
2015
|
+
this._defer.prune(started);
|
|
2016
|
+
this._deps.breaker.passed();
|
|
2017
|
+
this._lowered = raised;
|
|
2018
|
+
return EMPTY_DRAIN;
|
|
2019
|
+
}
|
|
2020
|
+
const { leased, fetched, handled, acked, blocked, closeable } = cycle;
|
|
2021
|
+
trace_cycle(this._deps.logger, leased, fetched, handled, acked, blocked);
|
|
2022
|
+
this._ratio = compute_lag_lead_ratio(handled, lagging, leading);
|
|
2023
|
+
for (const lease of acked) this._defer.delete(lease.stream);
|
|
2024
|
+
for (const lease of blocked) this._defer.delete(lease.stream);
|
|
2025
|
+
for (const h of handled) {
|
|
2026
|
+
const next = _nullishCoalesce(h.defer, () => ( h.next_attempt_at));
|
|
2027
|
+
if (next !== void 0) this._defer.set(h.lease.stream, next);
|
|
2028
|
+
}
|
|
2029
|
+
if (acked.length) this._deps.on_acked(acked);
|
|
2030
|
+
if (closeable.length) await this._deps.on_close(closeable);
|
|
2031
|
+
this._deps.breaker.passed();
|
|
2032
|
+
return { fetched, leased, acked, blocked };
|
|
2033
|
+
} catch (error) {
|
|
2034
|
+
this._defer.set(
|
|
2035
|
+
RETRY,
|
|
2036
|
+
Date.now() + Math.max(leaseMillis, this._deps.breaker.cooldown_ms)
|
|
2037
|
+
);
|
|
2038
|
+
this._deps.breaker.failed(Date.now(), error);
|
|
2039
|
+
return EMPTY_DRAIN;
|
|
2040
|
+
} finally {
|
|
2041
|
+
if (!this._stopped) this._defer.schedule();
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
}, _class3);
|
|
2045
|
+
|
|
2046
|
+
// src/internal/reaction-dispatch.ts
|
|
2047
|
+
var CloseSignal = class extends Error {
|
|
2048
|
+
/**
|
|
2049
|
+
* Stream to close. Omitted → the reaction's own lease stream (a self-close).
|
|
2050
|
+
* The synthesized autoclose reaction sets it to the aggregate stream, since
|
|
2051
|
+
* its lease runs on a synthetic `__autoclose__` target.
|
|
2052
|
+
*/
|
|
2053
|
+
|
|
2054
|
+
/** Optional archive callback to run while the stream is guarded. */
|
|
2055
|
+
|
|
2056
|
+
/**
|
|
2057
|
+
* Watermark to ack the requesting reaction to before the close runs. The
|
|
2058
|
+
* close-cycle safety guard skips a stream whose subscriptions (matched by
|
|
2059
|
+
* source) lag the head; the autoclose reaction's `source` is the aggregate,
|
|
2060
|
+
* so it must advance its own watermark to the live head id it evaluated
|
|
2061
|
+
* against — otherwise it blocks its own close. Defaults to the triggering
|
|
2062
|
+
* event id when omitted.
|
|
2063
|
+
*/
|
|
2064
|
+
|
|
2065
|
+
/**
|
|
2066
|
+
* Windowed close: prune events older than this cutoff behind
|
|
2067
|
+
* the closest safe snapshot instead of retiring the stream. Thrown by
|
|
2068
|
+
* the autoclose reaction of a `.autocloses({ keep })` state; flows
|
|
2069
|
+
* into {@link CloseTarget.before}. Omitted → a full close.
|
|
2070
|
+
*/
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Revisit the requesting reaction at this time. Only useful with an `at`
|
|
2074
|
+
* below the head: a reaction runs only when an event is waiting for it.
|
|
2075
|
+
*/
|
|
2076
|
+
|
|
2077
|
+
constructor(opts) {
|
|
2078
|
+
super("reaction requested close");
|
|
2079
|
+
this.name = "CloseSignal";
|
|
2080
|
+
this.stream = _optionalChain([opts, 'optionalAccess', _109 => _109.stream]);
|
|
2081
|
+
this.archive = _optionalChain([opts, 'optionalAccess', _110 => _110.archive]);
|
|
2082
|
+
this.at = _optionalChain([opts, 'optionalAccess', _111 => _111.at]);
|
|
2083
|
+
this.before = _optionalChain([opts, 'optionalAccess', _112 => _112.before]);
|
|
2084
|
+
this.defer = _optionalChain([opts, 'optionalAccess', _113 => _113.defer]);
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
function build_handle(deps) {
|
|
2088
|
+
const { logger, reaction_scope } = deps;
|
|
2089
|
+
return async (lease, payloads) => {
|
|
2090
|
+
if (payloads.length === 0) return { lease, handled: 0, acked_at: lease.at };
|
|
2091
|
+
const stream = lease.stream;
|
|
2092
|
+
const last_index_of = /* @__PURE__ */ new Map();
|
|
2093
|
+
for (let i = 0; i < payloads.length; i++)
|
|
2094
|
+
last_index_of.set(payloads[i].event.id, i);
|
|
2095
|
+
let at = lease.at;
|
|
2096
|
+
let handled = 0;
|
|
2097
|
+
if (lease.retry > 0)
|
|
2098
|
+
logger.warn(
|
|
2099
|
+
`Retrying ${stream}@${payloads.at(0).event.id} (${lease.retry}).`
|
|
2100
|
+
);
|
|
2101
|
+
for (let i = 0; i < payloads.length; i++) {
|
|
2102
|
+
const payload = payloads[i];
|
|
2103
|
+
const { event, handler } = payload;
|
|
2104
|
+
try {
|
|
2105
|
+
await reaction_scope.run(
|
|
2106
|
+
event,
|
|
2107
|
+
() => handler(event, stream, reaction_scope.app)
|
|
2108
|
+
);
|
|
2109
|
+
if (last_index_of.get(event.id) === i) {
|
|
2110
|
+
at = event.id;
|
|
2111
|
+
handled++;
|
|
2112
|
+
}
|
|
2113
|
+
} catch (error) {
|
|
2114
|
+
if (error instanceof _chunkBCA423WPcjs.DeferSignal) {
|
|
2115
|
+
let defer;
|
|
2116
|
+
try {
|
|
2117
|
+
defer = resolve_defer_at(error.when, event);
|
|
2118
|
+
} catch (invalid) {
|
|
2119
|
+
return finalize(
|
|
2120
|
+
lease,
|
|
2121
|
+
handled,
|
|
2122
|
+
at,
|
|
2123
|
+
invalid,
|
|
2124
|
+
payload.options,
|
|
2125
|
+
logger,
|
|
2126
|
+
event.id
|
|
2127
|
+
);
|
|
2128
|
+
}
|
|
2129
|
+
return { lease, handled, acked_at: at, defer };
|
|
2130
|
+
}
|
|
2131
|
+
if (error instanceof CloseSignal)
|
|
2132
|
+
return {
|
|
2133
|
+
lease,
|
|
2134
|
+
handled: handled + 1,
|
|
2135
|
+
// Advance to the live head the handler evaluated against (when
|
|
2136
|
+
// provided) so the close-cycle guard sees this reaction caught up.
|
|
2137
|
+
acked_at: _nullishCoalesce(error.at, () => ( event.id)),
|
|
2138
|
+
defer: _optionalChain([error, 'access', _114 => _114.defer, 'optionalAccess', _115 => _115.getTime, 'call', _116 => _116()]),
|
|
2139
|
+
// Close the signalled stream (the autoclose reaction's aggregate,
|
|
2140
|
+
// which differs from its synthetic lease stream); a self-closing
|
|
2141
|
+
// user reaction omits it and closes its own lease stream. A
|
|
2142
|
+
// carried `before` makes it a windowed close (prune, not retire).
|
|
2143
|
+
close: {
|
|
2144
|
+
stream: _nullishCoalesce(error.stream, () => ( stream)),
|
|
2145
|
+
archive: error.archive,
|
|
2146
|
+
before: error.before
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
return finalize(
|
|
2150
|
+
lease,
|
|
2151
|
+
handled,
|
|
2152
|
+
at,
|
|
2153
|
+
error,
|
|
2154
|
+
payload.options,
|
|
2155
|
+
logger,
|
|
2156
|
+
event.id
|
|
2157
|
+
);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return finalize(lease, handled, at, void 0, payloads[0].options, logger);
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
function build_handle_batch(logger) {
|
|
2164
|
+
return async (lease, payloads, batchHandler) => {
|
|
2165
|
+
const stream = lease.stream;
|
|
2166
|
+
const events = [];
|
|
2167
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2168
|
+
for (const p of payloads) {
|
|
2169
|
+
if (seen.has(p.event.id)) continue;
|
|
2170
|
+
seen.add(p.event.id);
|
|
2171
|
+
events.push(p.event);
|
|
2172
|
+
}
|
|
2173
|
+
const options = payloads[0].options;
|
|
2174
|
+
if (lease.retry > 0)
|
|
2175
|
+
logger.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);
|
|
2176
|
+
try {
|
|
2177
|
+
await batchHandler(events, stream);
|
|
2178
|
+
return finalize(
|
|
2179
|
+
lease,
|
|
2180
|
+
events.length,
|
|
2181
|
+
events.at(-1).id,
|
|
2182
|
+
void 0,
|
|
2183
|
+
options,
|
|
2184
|
+
logger
|
|
2185
|
+
);
|
|
2186
|
+
} catch (error) {
|
|
2187
|
+
return finalize(lease, 0, lease.at, error, options, logger);
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
// src/internal/autoclose-reaction.ts
|
|
2193
|
+
var AUTOCLOSE_TARGET_PREFIX = "__autoclose__:";
|
|
2194
|
+
function synthesize_autoclose_reactions(registry, states, read_window) {
|
|
2195
|
+
for (const st of states.values()) {
|
|
2196
|
+
const predicate = st.autoclose;
|
|
2197
|
+
if (!predicate) continue;
|
|
2198
|
+
const after_windows = st.autoclose_after_windows;
|
|
2199
|
+
const keep_days = st.autoclose_keep_days;
|
|
2200
|
+
const archiver = st.archive;
|
|
2201
|
+
const reaction = {
|
|
2202
|
+
// Run on a SYNTHETIC stream — `source` is the aggregate, `target` is a
|
|
2203
|
+
// per-aggregate `__autoclose__` key — so the autoclose reaction never
|
|
2204
|
+
// shares a watermark with the aggregate's own reactions. A shared
|
|
2205
|
+
// watermark would let autoclose's defer short-circuit the aggregate's
|
|
2206
|
+
// other reactions (the "a defer affects all reactions on a stream"
|
|
2207
|
+
// hazard). The close still targets the aggregate (`source`).
|
|
2208
|
+
// A stream name with a regex metacharacter would read as a pattern, and a
|
|
2209
|
+
// store may refuse it at subscribe, stopping every reaction. Such a stream
|
|
2210
|
+
// has no autoclose: `app.close` still closes it.
|
|
2211
|
+
resolver: (e) => _chunk4UWU5FANcjs.is_literal_source.call(void 0, e.stream) ? {
|
|
2212
|
+
target: `${AUTOCLOSE_TARGET_PREFIX}${e.stream}`,
|
|
2213
|
+
source: e.stream
|
|
2214
|
+
} : void 0,
|
|
2215
|
+
// Never block on autoclose: a transient query/store error should retry,
|
|
2216
|
+
// not quarantine the synthetic stream.
|
|
2217
|
+
options: { blockOnError: false, maxRetries: _chunk4UWU5FANcjs.DEFAULT_MAX_RETRIES },
|
|
2218
|
+
handler: async (event) => {
|
|
2219
|
+
const aggregate = event.stream;
|
|
2220
|
+
const window = read_window();
|
|
2221
|
+
if (!in_autoclose_window(window, /* @__PURE__ */ new Date()))
|
|
2222
|
+
throw new (0, _chunkBCA423WPcjs.DeferSignal)({ at: next_window_open(window, /* @__PURE__ */ new Date()) });
|
|
2223
|
+
const stats = await _chunk4UWU5FANcjs.store.call(void 0, ).query_stats([aggregate], {
|
|
2224
|
+
count: true,
|
|
2225
|
+
tail: keep_days !== void 0 ? true : void 0,
|
|
2226
|
+
exclude: [_chunkBCA423WPcjs.TOMBSTONE_EVENT, _chunkBCA423WPcjs.SNAP_EVENT]
|
|
2227
|
+
});
|
|
2228
|
+
const entry = stats.get(aggregate);
|
|
2229
|
+
if (!entry) return;
|
|
2230
|
+
const head = entry.head;
|
|
2231
|
+
if (predicate(aggregate, head, entry.count))
|
|
2232
|
+
throw new CloseSignal({
|
|
2233
|
+
stream: aggregate,
|
|
2234
|
+
archive: archiver ? () => archiver(aggregate, head) : void 0,
|
|
2235
|
+
// Ack this reaction's own watermark to the live head so the
|
|
2236
|
+
// close-cycle guard (which matches subscriptions by source =
|
|
2237
|
+
// aggregate) sees it caught up instead of blocking its own close.
|
|
2238
|
+
at: head.id
|
|
2239
|
+
});
|
|
2240
|
+
if (keep_days !== void 0) {
|
|
2241
|
+
const cutoff = days_before_now(keep_days);
|
|
2242
|
+
if (entry.tail.created < cutoff) {
|
|
2243
|
+
const waiting = after_windows.some(
|
|
2244
|
+
(days) => days_after(head.created, days).getTime() > Date.now()
|
|
2245
|
+
);
|
|
2246
|
+
throw new CloseSignal({
|
|
2247
|
+
stream: aggregate,
|
|
2248
|
+
before: cutoff,
|
|
2249
|
+
archive: archiver ? () => archiver(aggregate, head, cutoff) : void 0,
|
|
2250
|
+
at: waiting ? head.id - 1 : head.id,
|
|
2251
|
+
defer: waiting ? days_after(/* @__PURE__ */ new Date(), 1) : void 0
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
const dues = [];
|
|
2256
|
+
for (const days of after_windows)
|
|
2257
|
+
dues.push(days_after(head.created, days));
|
|
2258
|
+
if (keep_days !== void 0)
|
|
2259
|
+
dues.push(days_after(entry.tail.created, keep_days));
|
|
2260
|
+
const future = dues.map((d) => d.getTime()).filter((t) => t > Date.now());
|
|
2261
|
+
if (future.length)
|
|
2262
|
+
throw new (0, _chunkBCA423WPcjs.DeferSignal)({ at: new Date(Math.min(...future)) });
|
|
2263
|
+
}
|
|
2264
|
+
};
|
|
2265
|
+
const key = `__autoclose_${st.name}`;
|
|
2266
|
+
for (const event_name of Object.keys(st.events)) {
|
|
2267
|
+
_optionalChain([registry, 'access', _117 => _117.events, 'access', _118 => _118[event_name], 'optionalAccess', _119 => _119.reactions, 'access', _120 => _120.set, 'call', _121 => _121(
|
|
2268
|
+
key,
|
|
2269
|
+
reaction
|
|
2270
|
+
)]);
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
// src/internal/close-cycle.ts
|
|
2276
|
+
var CLOSE_CATCH_UP_LIMIT = 1e3;
|
|
2277
|
+
var CLOSE_CATCH_UP_PASSES = 20;
|
|
2278
|
+
async function catch_up_correlation(cursor, correlate, until) {
|
|
2279
|
+
for (let pass = 0; pass < CLOSE_CATCH_UP_PASSES && cursor.checkpoint < until; pass++) {
|
|
2280
|
+
const before = cursor.checkpoint;
|
|
2281
|
+
cursor.arm();
|
|
2282
|
+
await correlate(CLOSE_CATCH_UP_LIMIT);
|
|
2283
|
+
if (cursor.checkpoint <= before) break;
|
|
2284
|
+
}
|
|
2285
|
+
return cursor.checkpoint;
|
|
2286
|
+
}
|
|
2287
|
+
var CloseLock = (_class4 = class {constructor() { _class4.prototype.__init9.call(this); }
|
|
2288
|
+
__init9() {this._tails = /* @__PURE__ */ new Map()}
|
|
2289
|
+
/** Run `work` after every earlier close of `stream` has settled. */
|
|
2290
|
+
run(stream, work) {
|
|
2291
|
+
const prev = _nullishCoalesce(this._tails.get(stream), () => ( Promise.resolve()));
|
|
2292
|
+
const next = prev.then(work, work);
|
|
2293
|
+
this._tails.set(stream, next);
|
|
2294
|
+
const cleanup = () => {
|
|
2295
|
+
if (this._tails.get(stream) === next) this._tails.delete(stream);
|
|
2296
|
+
};
|
|
2297
|
+
next.then(cleanup, cleanup);
|
|
2298
|
+
return next;
|
|
2299
|
+
}
|
|
2300
|
+
}, _class4);
|
|
2301
|
+
var SAFETY_PROBE_PAGE_SIZE = 1e3;
|
|
2302
|
+
async function run_close_cycle(targets, deps) {
|
|
2303
|
+
const target_map = new Map(targets.map((t) => [t.stream, t]));
|
|
2304
|
+
for (const t of target_map.values()) {
|
|
2305
|
+
if (t.before !== void 0 && t.restart)
|
|
2306
|
+
throw new Error(
|
|
2307
|
+
`close: \`before\` and \`restart\` are mutually exclusive (stream "${t.stream}") \u2014 a windowed close keeps the stream live behind a real snapshot; restart reseeds it`
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
const windowed = [...target_map.values()].filter(
|
|
2311
|
+
(t) => t.before !== void 0
|
|
2312
|
+
);
|
|
2313
|
+
const full = [...target_map.values()].filter((t) => t.before === void 0);
|
|
2314
|
+
const skipped = [];
|
|
2315
|
+
const windowed_result = windowed.length ? await run_windowed_closes(windowed, deps, skipped) : /* @__PURE__ */ new Map();
|
|
2316
|
+
if (!full.length) return { truncated: windowed_result, skipped };
|
|
2317
|
+
const truncated = await with_stream_locks(
|
|
2318
|
+
full.map((t) => t.stream),
|
|
2319
|
+
deps,
|
|
2320
|
+
() => run_full_closes(full, target_map, deps, skipped)
|
|
2321
|
+
);
|
|
2322
|
+
const retired = [...truncated.entries()].filter(([, r]) => r.committed.name === _chunkBCA423WPcjs.TOMBSTONE_EVENT).map(([stream]) => stream);
|
|
2323
|
+
if (retired.length) _optionalChain([deps, 'access', _122 => _122.forget_subscribed, 'optionalCall', _123 => _123(retired)]);
|
|
2324
|
+
for (const [stream, entry] of windowed_result) truncated.set(stream, entry);
|
|
2325
|
+
return { truncated, skipped };
|
|
2326
|
+
}
|
|
2327
|
+
function with_stream_locks(streams, deps, work) {
|
|
2328
|
+
const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, w) => w())));
|
|
2329
|
+
return [...streams].sort().reduceRight(
|
|
2330
|
+
(inner, stream) => () => with_lock(stream, inner),
|
|
2331
|
+
work
|
|
2332
|
+
)();
|
|
2333
|
+
}
|
|
2334
|
+
async function run_full_closes(full, target_map, deps, skipped) {
|
|
2335
|
+
const none = /* @__PURE__ */ new Map();
|
|
2336
|
+
const streams = full.map((t) => t.stream);
|
|
2337
|
+
const stream_info = await scan_stream_heads(streams);
|
|
2338
|
+
for (const target of full) {
|
|
2339
|
+
if (!target.restart) continue;
|
|
2340
|
+
const info = stream_info.get(target.stream);
|
|
2341
|
+
if (!info) continue;
|
|
2342
|
+
const owner = deps.event_to_state.get(info.last_event_name);
|
|
2343
|
+
if (_optionalChain([owner, 'optionalAccess', _124 => _124.pii_aware])) {
|
|
2344
|
+
deps.logger.error(
|
|
2345
|
+
`Refusing to close "${target.stream}" with restart: state "${owner.name}" carries sensitive fields, so a restart seed would persist redacted values while deleting the originals. Close it without restart to retire the stream, or leave it open.`
|
|
2346
|
+
);
|
|
2347
|
+
skipped.push(target.stream);
|
|
2348
|
+
stream_info.delete(target.stream);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
const safe = await partition_by_safety(
|
|
2352
|
+
stream_info,
|
|
2353
|
+
deps.reactive,
|
|
2354
|
+
skipped,
|
|
2355
|
+
_nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
|
|
2356
|
+
deps.catch_up_correlation
|
|
2357
|
+
);
|
|
2358
|
+
if (!safe.length) return none;
|
|
2359
|
+
const { guarded, guard_events } = await guard_with_tombstones(
|
|
2360
|
+
safe,
|
|
2361
|
+
stream_info,
|
|
2362
|
+
deps.correlation,
|
|
2363
|
+
deps.tombstone,
|
|
2364
|
+
skipped
|
|
2365
|
+
);
|
|
2366
|
+
if (!guarded.length) return none;
|
|
2367
|
+
const seed_states = await load_restart_seeds(
|
|
2368
|
+
guarded,
|
|
2369
|
+
target_map,
|
|
2370
|
+
stream_info,
|
|
2371
|
+
deps.event_to_state,
|
|
2372
|
+
deps.load,
|
|
2373
|
+
deps.logger
|
|
2374
|
+
);
|
|
2375
|
+
await run_archive_callbacks(guarded, target_map);
|
|
2376
|
+
const still_guarded = await heads_still_guarded(
|
|
2377
|
+
guarded,
|
|
2378
|
+
guard_events,
|
|
2379
|
+
skipped
|
|
2380
|
+
);
|
|
2381
|
+
if (!still_guarded.length) return none;
|
|
2382
|
+
return truncate_and_warm_cache(
|
|
2383
|
+
still_guarded,
|
|
2384
|
+
seed_states,
|
|
2385
|
+
guard_events,
|
|
2386
|
+
deps.correlation
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2389
|
+
async function run_windowed_closes(windowed, deps, skipped) {
|
|
2390
|
+
const checkpoint = deps.reactive ? await deps.catch_up_correlation(Number.MAX_SAFE_INTEGER) : -1;
|
|
2391
|
+
const min_at = deps.reactive ? await probe_min_watermarks(
|
|
2392
|
+
windowed.map((t) => t.stream),
|
|
2393
|
+
_nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
|
|
2394
|
+
checkpoint
|
|
2395
|
+
) : /* @__PURE__ */ new Map();
|
|
2396
|
+
const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, work) => work())));
|
|
2397
|
+
const truncated = /* @__PURE__ */ new Map();
|
|
2398
|
+
for (const t of windowed) {
|
|
2399
|
+
const entry = await with_lock(t.stream, async () => {
|
|
2400
|
+
const max_id = min_at.get(t.stream);
|
|
2401
|
+
if (!await windowed_prune_pending(t.stream, t.before, max_id))
|
|
2402
|
+
return void 0;
|
|
2403
|
+
if (t.archive) await t.archive();
|
|
2404
|
+
const result = await _chunk4UWU5FANcjs.store.call(void 0, ).truncate([
|
|
2405
|
+
{ stream: t.stream, before: t.before, max_id }
|
|
2406
|
+
]);
|
|
2407
|
+
return result.get(t.stream);
|
|
2408
|
+
});
|
|
2409
|
+
if (entry) truncated.set(t.stream, entry);
|
|
2410
|
+
else skipped.push(t.stream);
|
|
2411
|
+
}
|
|
2412
|
+
return truncated;
|
|
2413
|
+
}
|
|
2414
|
+
async function windowed_prune_pending(stream, before, max_id) {
|
|
2415
|
+
let boundary_id;
|
|
2416
|
+
let min_id;
|
|
2417
|
+
await _chunk4UWU5FANcjs.store.call(void 0, ).query(
|
|
2418
|
+
(event) => {
|
|
2419
|
+
if (min_id === void 0 || event.id < min_id) min_id = event.id;
|
|
2420
|
+
if (event.name === _chunkBCA423WPcjs.SNAP_EVENT && event.created < before && (max_id === void 0 || event.id <= max_id) && (boundary_id === void 0 || event.id > boundary_id))
|
|
2421
|
+
boundary_id = event.id;
|
|
2422
|
+
},
|
|
2423
|
+
{ stream, stream_exact: true, with_snaps: true, after: -1 }
|
|
2424
|
+
);
|
|
2425
|
+
return boundary_id !== void 0 && min_id < boundary_id;
|
|
2426
|
+
}
|
|
2427
|
+
async function probe_min_watermarks(streams, page_size, checkpoint) {
|
|
2428
|
+
const min_at = /* @__PURE__ */ new Map();
|
|
2429
|
+
const matches = source_matcher();
|
|
2430
|
+
await walk_streams(
|
|
2431
|
+
_chunk4UWU5FANcjs.store.call(void 0, ),
|
|
2432
|
+
(position) => {
|
|
2433
|
+
const pending = position.correlated_at === void 0 || position.at < position.correlated_at;
|
|
2434
|
+
const cap = pending ? position.at : Math.max(position.at, checkpoint);
|
|
2435
|
+
for (const stream of streams) {
|
|
2436
|
+
if (matches(position.source, position.stream, stream)) {
|
|
2437
|
+
const prev = min_at.get(stream);
|
|
2438
|
+
if (prev === void 0 || cap < prev) min_at.set(stream, cap);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
},
|
|
2442
|
+
{ limit: page_size }
|
|
2443
|
+
);
|
|
2444
|
+
return min_at;
|
|
2445
|
+
}
|
|
2446
|
+
function source_matcher() {
|
|
2447
|
+
const compiled = /* @__PURE__ */ new Map();
|
|
2448
|
+
return (source, target, stream) => {
|
|
2449
|
+
if (!source) return true;
|
|
2450
|
+
if (_chunk4UWU5FANcjs.is_literal_source.call(void 0, source, target)) return source === stream;
|
|
2451
|
+
let re = compiled.get(source);
|
|
2452
|
+
if (!re) {
|
|
2453
|
+
re = new RegExp(source);
|
|
2454
|
+
compiled.set(source, re);
|
|
2455
|
+
}
|
|
2456
|
+
return re.test(stream);
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
async function scan_stream_heads(streams) {
|
|
2460
|
+
const stats = await _chunk4UWU5FANcjs.store.call(void 0, ).query_stats(streams, {
|
|
2461
|
+
exclude: [_chunkBCA423WPcjs.SNAP_EVENT]
|
|
2462
|
+
});
|
|
2463
|
+
const domain_heads = await _chunk4UWU5FANcjs.store.call(void 0, ).query_stats(streams, {
|
|
2464
|
+
exclude: [_chunkBCA423WPcjs.SNAP_EVENT, _chunkBCA423WPcjs.TOMBSTONE_EVENT]
|
|
2465
|
+
});
|
|
2466
|
+
const true_heads = await _chunk4UWU5FANcjs.store.call(void 0, ).query_stats(streams, {});
|
|
2467
|
+
const out = /* @__PURE__ */ new Map();
|
|
2468
|
+
for (const [stream, { head }] of domain_heads) {
|
|
2469
|
+
const marker_head = _optionalChain([stats, 'access', _125 => _125.get, 'call', _126 => _126(stream), 'optionalAccess', _127 => _127.head]);
|
|
2470
|
+
const interrupted = _optionalChain([marker_head, 'optionalAccess', _128 => _128.name]) === _chunkBCA423WPcjs.TOMBSTONE_EVENT;
|
|
2471
|
+
out.set(stream, {
|
|
2472
|
+
max_id: head.id,
|
|
2473
|
+
version: true_heads.get(stream).head.version,
|
|
2474
|
+
last_event_name: head.name,
|
|
2475
|
+
...interrupted ? { resumed_guard: { id: marker_head.id } } : {}
|
|
2476
|
+
});
|
|
2477
|
+
}
|
|
2478
|
+
return out;
|
|
2479
|
+
}
|
|
2480
|
+
async function partition_by_safety(stream_info, reactive, skipped, page_size, catch_up_correlation2) {
|
|
2481
|
+
if (!reactive) return [...stream_info.keys()];
|
|
2482
|
+
let needed = -1;
|
|
2483
|
+
for (const info of stream_info.values())
|
|
2484
|
+
needed = Math.max(needed, info.max_id);
|
|
2485
|
+
const checkpoint = await catch_up_correlation2(needed);
|
|
2486
|
+
const uncorrelated = /* @__PURE__ */ new Set();
|
|
2487
|
+
for (const [stream, info] of stream_info) {
|
|
2488
|
+
if (checkpoint < info.max_id) uncorrelated.add(stream);
|
|
2489
|
+
}
|
|
2490
|
+
const pending_set = /* @__PURE__ */ new Set();
|
|
2491
|
+
const matches = source_matcher();
|
|
2492
|
+
await walk_streams(
|
|
2493
|
+
_chunk4UWU5FANcjs.store.call(void 0, ),
|
|
2494
|
+
(position) => {
|
|
2495
|
+
const has_work = position.correlated_at !== void 0 && position.at < position.correlated_at;
|
|
2496
|
+
if (!has_work) return;
|
|
2497
|
+
if (position.stream.startsWith(AUTOCLOSE_TARGET_PREFIX)) return;
|
|
2498
|
+
for (const [stream, info] of stream_info) {
|
|
2499
|
+
if (matches(position.source, position.stream, stream) && position.at < info.max_id)
|
|
2500
|
+
pending_set.add(stream);
|
|
2501
|
+
}
|
|
2502
|
+
},
|
|
2503
|
+
{ limit: page_size }
|
|
2504
|
+
);
|
|
2505
|
+
const safe = [];
|
|
2506
|
+
for (const [stream] of stream_info) {
|
|
2507
|
+
if (pending_set.has(stream) || uncorrelated.has(stream))
|
|
2508
|
+
skipped.push(stream);
|
|
2509
|
+
else safe.push(stream);
|
|
2510
|
+
}
|
|
2511
|
+
return safe;
|
|
2512
|
+
}
|
|
2513
|
+
async function guard_with_tombstones(safe, stream_info, correlation, tombstone2, skipped) {
|
|
2514
|
+
const guarded = [];
|
|
2515
|
+
const guard_events = /* @__PURE__ */ new Map();
|
|
2516
|
+
await Promise.all(
|
|
2517
|
+
safe.map(async (stream) => {
|
|
2518
|
+
const info = stream_info.get(stream);
|
|
2519
|
+
if (info.resumed_guard) {
|
|
2520
|
+
guarded.push(stream);
|
|
2521
|
+
guard_events.set(stream, { id: info.resumed_guard.id, stream });
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
const committed = await tombstone2(stream, info.version, correlation);
|
|
2525
|
+
if (committed) {
|
|
2526
|
+
guarded.push(stream);
|
|
2527
|
+
guard_events.set(stream, { id: committed.id, stream });
|
|
2528
|
+
} else {
|
|
2529
|
+
skipped.push(stream);
|
|
2205
2530
|
}
|
|
2206
|
-
}
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
else if (ack_part) tail = ` ${ack_part}`;
|
|
2210
|
-
else if (fail_part) tail = ` ${fail_part}`;
|
|
2211
|
-
else tail = ` ${dim(`\u2298 @${at}/${retry}`)}`;
|
|
2212
|
-
return `${key}${events}${tail}`;
|
|
2213
|
-
}).join(", ");
|
|
2214
|
-
logger.trace(`${drain_caption("drained", lane)} ${detail}`);
|
|
2215
|
-
}
|
|
2216
|
-
|
|
2217
|
-
// src/internal/drain-cycle.ts
|
|
2218
|
-
function budget_exhausted(lease, options, store_failing) {
|
|
2219
|
-
if (store_failing || !_optionalChain([options, 'optionalAccess', _110 => _110.blockOnError]) || lease.retry <= options.maxRetries)
|
|
2220
|
-
return void 0;
|
|
2221
|
-
const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress \u2014 the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. That means every attempt lost its lease before it could ack: move the reaction to a lane whose leaseMillis covers the handler, then unblock the stream.`;
|
|
2222
|
-
_chunkPRDX3HP6cjs.log.call(void 0, ).error(error);
|
|
2223
|
-
return { lease, handled: 0, acked_at: lease.at, error, block: true };
|
|
2531
|
+
})
|
|
2532
|
+
);
|
|
2533
|
+
return { guarded, guard_events };
|
|
2224
2534
|
}
|
|
2225
|
-
function
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2535
|
+
async function load_restart_seeds(guarded, target_map, stream_info, event_to_state, load2, logger) {
|
|
2536
|
+
const seed_states = /* @__PURE__ */ new Map();
|
|
2537
|
+
await Promise.all(
|
|
2538
|
+
guarded.filter((s) => _optionalChain([target_map, 'access', _129 => _129.get, 'call', _130 => _130(s), 'optionalAccess', _131 => _131.restart])).map(async (stream) => {
|
|
2539
|
+
const last_event_name = stream_info.get(stream).last_event_name;
|
|
2540
|
+
const owner_state = event_to_state.get(last_event_name);
|
|
2541
|
+
if (!owner_state) {
|
|
2542
|
+
logger.error(
|
|
2543
|
+
`Cannot seed restart for "${stream}": no registered state owns event "${last_event_name}". Stream will be tombstoned instead.`
|
|
2544
|
+
);
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
const snap2 = await load2(owner_state, { stream });
|
|
2548
|
+
seed_states.set(stream, snap2.state);
|
|
2549
|
+
})
|
|
2550
|
+
);
|
|
2551
|
+
return seed_states;
|
|
2234
2552
|
}
|
|
2235
|
-
function
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
if (block2)
|
|
2241
|
-
logger.error(
|
|
2242
|
-
non_retryable ? `Blocking ${lease.stream} on non-retryable error.` : `Blocking ${lease.stream} after ${lease.retry} retries.`
|
|
2243
|
-
);
|
|
2244
|
-
const next_attempt_at = block2 ? void 0 : Date.now() + compute_backoff_delay(lease.retry, _nullishCoalesce(options.backoff, () => ( _chunkPRDX3HP6cjs.DEFAULT_BACKOFF)));
|
|
2245
|
-
return {
|
|
2246
|
-
lease,
|
|
2247
|
-
handled,
|
|
2248
|
-
acked_at: at,
|
|
2249
|
-
error: error.message,
|
|
2250
|
-
block: block2,
|
|
2251
|
-
next_attempt_at,
|
|
2252
|
-
failed_at
|
|
2253
|
-
};
|
|
2553
|
+
async function run_archive_callbacks(guarded, target_map) {
|
|
2554
|
+
for (const stream of guarded) {
|
|
2555
|
+
const archive_fn = _optionalChain([target_map, 'access', _132 => _132.get, 'call', _133 => _133(stream), 'optionalAccess', _134 => _134.archive]);
|
|
2556
|
+
if (archive_fn) await archive_fn();
|
|
2557
|
+
}
|
|
2254
2558
|
}
|
|
2255
|
-
function
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2559
|
+
async function heads_still_guarded(guarded, guard_events, skipped) {
|
|
2560
|
+
const heads = await _chunk4UWU5FANcjs.store.call(void 0, ).query_stats(guarded, {});
|
|
2561
|
+
return guarded.filter((stream) => {
|
|
2562
|
+
if (_optionalChain([heads, 'access', _135 => _135.get, 'call', _136 => _136(stream), 'optionalAccess', _137 => _137.head, 'access', _138 => _138.id]) === guard_events.get(stream).id)
|
|
2563
|
+
return true;
|
|
2564
|
+
skipped.push(stream);
|
|
2565
|
+
return false;
|
|
2566
|
+
});
|
|
2261
2567
|
}
|
|
2262
|
-
async function
|
|
2263
|
-
const
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
lagging,
|
|
2274
|
-
leading,
|
|
2275
|
-
_crypto.randomUUID.call(void 0, ),
|
|
2276
|
-
leaseMillis,
|
|
2277
|
-
lane
|
|
2278
|
-
);
|
|
2279
|
-
if (!leased.length) return void 0;
|
|
2280
|
-
const fetched = await ops.fetch(leased, eventLimit);
|
|
2281
|
-
const fetch_map = /* @__PURE__ */ new Map();
|
|
2282
|
-
const fetch_window_at = fetched.reduce(
|
|
2283
|
-
(max, { at, events }) => Math.max(max, _optionalChain([events, 'access', _111 => _111.at, 'call', _112 => _112(-1), 'optionalAccess', _113 => _113.id]) || at),
|
|
2284
|
-
0
|
|
2285
|
-
);
|
|
2286
|
-
for (const f of fetched) {
|
|
2287
|
-
const { stream, events } = f;
|
|
2288
|
-
let failed;
|
|
2289
|
-
const payloads = events.flatMap((event) => {
|
|
2290
|
-
const register = registry.events[event.name];
|
|
2291
|
-
if (!register) return [];
|
|
2292
|
-
return [...register.reactions.values()].filter((reaction) => {
|
|
2293
|
-
const resolver = reaction.resolver;
|
|
2294
|
-
const dynamic = typeof resolver === "function";
|
|
2295
|
-
let resolved;
|
|
2296
|
-
try {
|
|
2297
|
-
resolved = dynamic ? resolver(event) : resolver;
|
|
2298
|
-
} catch (error) {
|
|
2299
|
-
failed ??= {
|
|
2300
|
-
error: new Error(
|
|
2301
|
-
`Resolver of reaction "${reaction.handler.name}" threw on ${String(event.name)} #${event.id} (stream "${event.stream}"): ${String(error)}`
|
|
2302
|
-
),
|
|
2303
|
-
options: reaction.options
|
|
2304
|
-
};
|
|
2305
|
-
return false;
|
|
2568
|
+
async function truncate_and_warm_cache(guarded, seed_states, guard_events, correlation) {
|
|
2569
|
+
const trunc_targets = guarded.map((stream) => {
|
|
2570
|
+
const snapshot = seed_states.get(stream);
|
|
2571
|
+
const guard = guard_events.get(stream);
|
|
2572
|
+
return {
|
|
2573
|
+
stream,
|
|
2574
|
+
snapshot,
|
|
2575
|
+
meta: {
|
|
2576
|
+
correlation,
|
|
2577
|
+
causation: {
|
|
2578
|
+
event: { id: guard.id, name: _chunkBCA423WPcjs.TOMBSTONE_EVENT, stream: guard.stream }
|
|
2306
2579
|
}
|
|
2307
|
-
if (!resolved || resolved.target !== stream) return false;
|
|
2308
|
-
if (!dynamic || !batch_handlers.has(stream)) return true;
|
|
2309
|
-
warn_misrouted(
|
|
2310
|
-
misrouted,
|
|
2311
|
-
stream,
|
|
2312
|
-
reaction.handler.name,
|
|
2313
|
-
String(event.name)
|
|
2314
|
-
);
|
|
2315
|
-
return false;
|
|
2316
|
-
}).map((reaction) => ({ ...reaction, event }));
|
|
2317
|
-
});
|
|
2318
|
-
fetch_map.set(stream, { fetch: f, payloads, failed });
|
|
2319
|
-
}
|
|
2320
|
-
const handled = await Promise.all(
|
|
2321
|
-
leased.map((lease) => {
|
|
2322
|
-
const entry = fetch_map.get(lease.stream);
|
|
2323
|
-
if (entry.fetch.error !== void 0) {
|
|
2324
|
-
const policy = fetch_failure_policy(registry);
|
|
2325
|
-
return Promise.resolve(
|
|
2326
|
-
finalize(
|
|
2327
|
-
lease,
|
|
2328
|
-
0,
|
|
2329
|
-
lease.at,
|
|
2330
|
-
new Error(`Fetch failed for ${lease.stream}: ${entry.fetch.error}`),
|
|
2331
|
-
store_failing ? { ...policy, blockOnError: false } : policy,
|
|
2332
|
-
deps.logger
|
|
2333
|
-
)
|
|
2334
|
-
);
|
|
2335
2580
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
if (exhausted) return Promise.resolve(exhausted);
|
|
2355
|
-
const batchHandler = batch_handlers.get(lease.stream);
|
|
2356
|
-
if (batchHandler && payloads.length > 0) {
|
|
2357
|
-
return handle_batch({ ...lease, at }, payloads, batchHandler);
|
|
2581
|
+
};
|
|
2582
|
+
});
|
|
2583
|
+
const truncated = await _chunk4UWU5FANcjs.store.call(void 0, ).truncate(trunc_targets);
|
|
2584
|
+
await Promise.all(
|
|
2585
|
+
guarded.map(async (stream) => {
|
|
2586
|
+
const entry = truncated.get(stream);
|
|
2587
|
+
const state2 = seed_states.get(stream);
|
|
2588
|
+
if (state2 && entry) {
|
|
2589
|
+
await _chunk4UWU5FANcjs.cache.call(void 0, ).set(stream, {
|
|
2590
|
+
stream,
|
|
2591
|
+
state: state2,
|
|
2592
|
+
version: entry.committed.version,
|
|
2593
|
+
event_id: entry.committed.id,
|
|
2594
|
+
patches: 0,
|
|
2595
|
+
snaps: 1
|
|
2596
|
+
});
|
|
2597
|
+
} else {
|
|
2598
|
+
await _chunk4UWU5FANcjs.cache.call(void 0, ).invalidate(stream);
|
|
2358
2599
|
}
|
|
2359
|
-
return handle({ ...lease, at }, payloads);
|
|
2360
2600
|
})
|
|
2361
2601
|
);
|
|
2362
|
-
|
|
2363
|
-
const blocked = to_block.length ? await ops.block(to_block) : [];
|
|
2364
|
-
if (blocked.length) deps.on_blocked(blocked);
|
|
2365
|
-
const submitted = handled.flatMap((h, i) => {
|
|
2366
|
-
const advance = h.handled > 0 ? h.acked_at : leased[i].at;
|
|
2367
|
-
return h.defer !== void 0 ? { ...h.lease, at: advance, due: h.defer, retry: -1 } : h.next_attempt_at !== void 0 ? { ...h.lease, at: advance, due: h.next_attempt_at } : h.handled > 0 || !h.error ? { ...h.lease, at: h.acked_at } : [];
|
|
2368
|
-
});
|
|
2369
|
-
const acked = submitted.length ? await ops.ack(submitted) : [];
|
|
2370
|
-
const expected = submitted.filter((l) => l.due === void 0).length;
|
|
2371
|
-
if (acked.length < expected)
|
|
2372
|
-
_chunkPRDX3HP6cjs.log.call(void 0, ).warn(
|
|
2373
|
-
`drain: ${expected - acked.length} of ${expected} acks were dropped \u2014 the lease was taken by another worker mid-handler. That work will be redelivered (at-least-once), but persistent drops mean leaseMillis is too short for this handler.`
|
|
2374
|
-
);
|
|
2375
|
-
const closeable = handled.filter((h) => h.close !== void 0).map((h) => h.close);
|
|
2376
|
-
return { leased, fetched, handled, acked, blocked, closeable };
|
|
2602
|
+
return truncated;
|
|
2377
2603
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2604
|
+
|
|
2605
|
+
// src/internal/correlate-cycle.ts
|
|
2606
|
+
|
|
2607
|
+
var COLD_START_BACK_SCAN = 1e4;
|
|
2608
|
+
var CORRELATION_LEASE_MS = 5e3;
|
|
2609
|
+
var registry_key = (events) => {
|
|
2610
|
+
const shape = Object.keys(events).filter((name) => events[name].reactions.size > 0).sort().map((name) => [name, [...events[name].reactions.keys()].sort()]);
|
|
2611
|
+
return _crypto.createHash.call(void 0, "sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 32);
|
|
2383
2612
|
};
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2613
|
+
var PATTERN_CACHE_SIZE = 32;
|
|
2614
|
+
function report_undeclared_lane(seen, handler, target, lane, declared) {
|
|
2615
|
+
report_once(
|
|
2616
|
+
seen,
|
|
2617
|
+
`lane|${handler}|${lane}`,
|
|
2618
|
+
`Reaction "${handler}" resolved onto undeclared lane "${lane}" \u2014 for example target "${target}". Declared lanes: ${[...declared].map((l) => `"${l}"`).join(", ")}. No controller claims it, so the stream would never drain \u2014 running it on "default" instead. The equivalent static \`.to({ lane })\` is rejected at build; a dynamic resolver's lane is only knowable here.`
|
|
2619
|
+
);
|
|
2391
2620
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
//
|
|
2402
|
-
|
|
2403
|
-
// drains until a pass leases nothing or the controller stops, and an entry
|
|
2404
|
-
// stays until handled or until a later pass claims nothing.
|
|
2405
|
-
__init18() {this._defer = new DeferTimer(() => {
|
|
2406
|
-
this.arm();
|
|
2407
|
-
void this._deps.run_scoped(async () => {
|
|
2408
|
-
while ((await this.drain()).leased.length > 0) ;
|
|
2409
|
-
});
|
|
2410
|
-
})}
|
|
2621
|
+
function report_lane_conflict(seen, handler, target, kept, dropped) {
|
|
2622
|
+
report_once(
|
|
2623
|
+
seen,
|
|
2624
|
+
`conflict|${handler}|${kept}|${dropped}`,
|
|
2625
|
+
`Reaction "${handler}" resolved lane "${dropped}" for a stream already on "${kept}" \u2014 for example "${target}". These are conflicting lane assignments from two dynamic resolutions at equal priority. Keeping "${kept}", the lane it was first discovered on \u2014 re-laning a live stream would move it out from under a worker holding its lease. The reaction resolving "${dropped}" runs inside the "${kept}" lane's budget, and a process restricted to "${dropped}" via onlyLanes never runs it. The equivalent static declaration is rejected at build; align the resolvers, or split the target.`
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2628
|
+
var CorrelateCycle = (_class5 = class {
|
|
2629
|
+
__init10() {this._checkpoint = -1}
|
|
2630
|
+
// Lease holder id; per instance, so a restart never inherits a stale claim.
|
|
2631
|
+
__init11() {this._by = _crypto.randomUUID.call(void 0, )}
|
|
2411
2632
|
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
//
|
|
2633
|
+
// Local expiry of the held lease (0 = none); stale only costs a duplicate scan.
|
|
2634
|
+
__init12() {this._lease_until = 0}
|
|
2635
|
+
// Armed while `_raised` (bumped by a commit or notification) is ahead of
|
|
2636
|
+
// `_lowered` (the raise count the last short page saw). Starts armed.
|
|
2637
|
+
__init13() {this._raised = 1}
|
|
2638
|
+
__init14() {this._lowered = 0}
|
|
2639
|
+
// Bumped by a release (shutdown), so a scan or lease reply that was out
|
|
2640
|
+
// across one writes nothing.
|
|
2641
|
+
__init15() {this._epoch = 0}
|
|
2642
|
+
// Passes in flight: a restore waits for them, and refuses new ones.
|
|
2643
|
+
__init16() {this._passes = /* @__PURE__ */ new Set()}
|
|
2644
|
+
__init17() {this._restoring = false}
|
|
2415
2645
|
|
|
2646
|
+
// Bounded by `maxSubscribedStreams`; static records live apart so eviction
|
|
2647
|
+
// never lets a resolution re-lane them.
|
|
2416
2648
|
|
|
2417
|
-
|
|
2418
|
-
|
|
2649
|
+
__init18() {this._static_subscriptions = /* @__PURE__ */ new Map()}
|
|
2650
|
+
__init19() {this._patterns = new (0, _chunk4UWU5FANcjs.LruMap)(PATTERN_CACHE_SIZE)}
|
|
2651
|
+
|
|
2652
|
+
|
|
2653
|
+
|
|
2654
|
+
|
|
2655
|
+
|
|
2656
|
+
// Report-once keys; per instance because `internal/` holds no module state.
|
|
2657
|
+
__init20() {this._reported = /* @__PURE__ */ new Set()}
|
|
2658
|
+
constructor({
|
|
2659
|
+
registry,
|
|
2660
|
+
static_targets,
|
|
2661
|
+
cd,
|
|
2662
|
+
max_subscribed_streams,
|
|
2663
|
+
declared_lanes,
|
|
2664
|
+
shard,
|
|
2665
|
+
on_init
|
|
2666
|
+
}) {;_class5.prototype.__init10.call(this);_class5.prototype.__init11.call(this);_class5.prototype.__init12.call(this);_class5.prototype.__init13.call(this);_class5.prototype.__init14.call(this);_class5.prototype.__init15.call(this);_class5.prototype.__init16.call(this);_class5.prototype.__init17.call(this);_class5.prototype.__init18.call(this);_class5.prototype.__init19.call(this);_class5.prototype.__init20.call(this);
|
|
2667
|
+
this._key = shard ? `${registry_key(registry.events)}:${[...shard].sort().join(",")}` : registry_key(registry.events);
|
|
2668
|
+
this._dynamic_subscriptions = new (0, _chunk4UWU5FANcjs.LruMap)(max_subscribed_streams);
|
|
2669
|
+
this._registry = registry;
|
|
2670
|
+
this._declared_lanes = declared_lanes;
|
|
2671
|
+
this._static_targets = static_targets;
|
|
2672
|
+
this._cd = cd;
|
|
2673
|
+
this._on_init = on_init;
|
|
2419
2674
|
}
|
|
2675
|
+
get checkpoint() {
|
|
2676
|
+
return this._checkpoint;
|
|
2677
|
+
}
|
|
2678
|
+
/** A commit (local or remote) may have produced uncorrelated events. */
|
|
2420
2679
|
arm() {
|
|
2421
2680
|
this._raised++;
|
|
2422
2681
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
return this._raised !== this._lowered;
|
|
2430
|
-
}
|
|
2431
|
-
get inflight() {
|
|
2432
|
-
return this._inflight;
|
|
2433
|
-
}
|
|
2434
|
-
/** This lane's configured lease, or `undefined`; the shutdown grace basis. */
|
|
2435
|
-
get lease_millis() {
|
|
2436
|
-
return _optionalChain([this, 'access', _121 => _121._deps, 'access', _122 => _122.defaults, 'optionalAccess', _123 => _123.leaseMillis]);
|
|
2682
|
+
async _init() {
|
|
2683
|
+
this._init_promise ??= this._run_init().catch((error) => {
|
|
2684
|
+
this._init_promise = void 0;
|
|
2685
|
+
throw error;
|
|
2686
|
+
});
|
|
2687
|
+
await this._init_promise;
|
|
2437
2688
|
}
|
|
2438
|
-
|
|
2439
|
-
|
|
2689
|
+
async _run_init() {
|
|
2690
|
+
const { watermark, correlated_at } = await this._cd.subscribe([
|
|
2691
|
+
...this._static_targets
|
|
2692
|
+
]);
|
|
2693
|
+
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - COLD_START_BACK_SCAN);
|
|
2694
|
+
for (const { stream, priority = 0, lane } of this._static_targets) {
|
|
2695
|
+
this._static_subscriptions.set(stream, {
|
|
2696
|
+
priority,
|
|
2697
|
+
lane
|
|
2698
|
+
});
|
|
2699
|
+
}
|
|
2700
|
+
await _optionalChain([this, 'access', _139 => _139._on_init, 'optionalCall', _140 => _140()]);
|
|
2440
2701
|
}
|
|
2441
2702
|
/**
|
|
2442
|
-
*
|
|
2443
|
-
*
|
|
2703
|
+
* Replace the log with no pass in flight, then cold-start: a pass that
|
|
2704
|
+
* read the old log writes before the restore, never into the new one.
|
|
2444
2705
|
*/
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
this.
|
|
2452
|
-
}
|
|
2453
|
-
this.
|
|
2454
|
-
this.
|
|
2706
|
+
async restart(restore) {
|
|
2707
|
+
this._restoring = true;
|
|
2708
|
+
try {
|
|
2709
|
+
await Promise.allSettled(this._passes);
|
|
2710
|
+
await restore();
|
|
2711
|
+
} finally {
|
|
2712
|
+
this._restoring = false;
|
|
2713
|
+
}
|
|
2714
|
+
this._init_promise = void 0;
|
|
2715
|
+
this._checkpoint = -1;
|
|
2716
|
+
this._dynamic_subscriptions.clear();
|
|
2717
|
+
this._static_subscriptions.clear();
|
|
2455
2718
|
}
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2719
|
+
/** Forget dynamic targets whose rows a full close deleted, so they re-subscribe. */
|
|
2720
|
+
forget_subscribed(streams) {
|
|
2721
|
+
for (const stream of streams) this._dynamic_subscriptions.delete(stream);
|
|
2722
|
+
}
|
|
2723
|
+
// Would the target's own `fetch` (filtered by `source`) return this event?
|
|
2724
|
+
_in_fetch_window(source, stream) {
|
|
2725
|
+
if (source === void 0 || source === stream) return true;
|
|
2726
|
+
if (_chunk4UWU5FANcjs.is_literal_source.call(void 0, source)) return false;
|
|
2727
|
+
let pattern = this._patterns.get(source);
|
|
2728
|
+
if (!pattern) {
|
|
2729
|
+
pattern = new RegExp(source);
|
|
2730
|
+
this._patterns.set(source, pattern);
|
|
2461
2731
|
}
|
|
2462
|
-
|
|
2732
|
+
return pattern.test(stream);
|
|
2463
2733
|
}
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
const
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2734
|
+
/** Scan past the checkpoint, subscribe new targets and raise their work marks. */
|
|
2735
|
+
async correlate(limit, lease = false) {
|
|
2736
|
+
if (this._restoring) return { kind: "idle", last_id: this._checkpoint };
|
|
2737
|
+
const pass = this._scan(limit, lease);
|
|
2738
|
+
this._passes.add(pass);
|
|
2739
|
+
try {
|
|
2740
|
+
return await pass;
|
|
2741
|
+
} finally {
|
|
2742
|
+
this._passes.delete(pass);
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
async _scan(limit, lease) {
|
|
2746
|
+
await this._init();
|
|
2747
|
+
const epoch = this._epoch;
|
|
2748
|
+
const idle = () => ({
|
|
2749
|
+
kind: "idle",
|
|
2750
|
+
last_id: this._checkpoint
|
|
2751
|
+
});
|
|
2752
|
+
if (this._raised === this._lowered) return idle();
|
|
2753
|
+
const raised = this._raised;
|
|
2754
|
+
const now = Date.now();
|
|
2755
|
+
if (lease && now >= this._lease_until - CORRELATION_LEASE_MS / 2) {
|
|
2756
|
+
const { correlating } = await this._cd.subscribe([], void 0, {
|
|
2757
|
+
key: this._key,
|
|
2758
|
+
by: this._by,
|
|
2759
|
+
millis: CORRELATION_LEASE_MS
|
|
2760
|
+
});
|
|
2761
|
+
if (this._epoch !== epoch) return idle();
|
|
2762
|
+
this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
|
|
2763
|
+
if (correlating === false) return idle();
|
|
2764
|
+
}
|
|
2765
|
+
const after = this._checkpoint;
|
|
2766
|
+
const correlated = /* @__PURE__ */ new Map();
|
|
2767
|
+
let last_id = after;
|
|
2768
|
+
let stopped = false;
|
|
2769
|
+
const found = await _chunk4UWU5FANcjs.store.call(void 0, ).query(
|
|
2770
|
+
(event) => {
|
|
2771
|
+
if (stopped) return;
|
|
2772
|
+
const register = this._registry.events[event.name];
|
|
2773
|
+
if (register) {
|
|
2774
|
+
for (const reaction of register.reactions.values()) {
|
|
2775
|
+
let resolved;
|
|
2776
|
+
try {
|
|
2777
|
+
resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
2778
|
+
} catch (error) {
|
|
2779
|
+
stopped = true;
|
|
2780
|
+
report_once(
|
|
2781
|
+
this._reported,
|
|
2782
|
+
`resolver|${reaction.handler.name}|${event.id}`,
|
|
2783
|
+
`Resolver of reaction "${reaction.handler.name}" threw on ${String(event.name)} #${event.id} (stream "${event.stream}"): ${String(error)}. Correlation stops before this event until the resolver stops throwing; work already found keeps draining.`
|
|
2784
|
+
);
|
|
2785
|
+
return;
|
|
2786
|
+
}
|
|
2787
|
+
if (!resolved) continue;
|
|
2788
|
+
let lane = resolved.lane;
|
|
2789
|
+
if (lane !== void 0 && !this._declared_lanes.has(lane)) {
|
|
2790
|
+
report_undeclared_lane(
|
|
2791
|
+
this._reported,
|
|
2792
|
+
reaction.handler.name,
|
|
2793
|
+
resolved.target,
|
|
2794
|
+
lane,
|
|
2795
|
+
this._declared_lanes
|
|
2796
|
+
);
|
|
2797
|
+
lane = void 0;
|
|
2798
|
+
}
|
|
2799
|
+
const fixed = this._static_subscriptions.get(resolved.target);
|
|
2800
|
+
const recorded = _nullishCoalesce(fixed, () => ( this._dynamic_subscriptions.get(resolved.target)));
|
|
2801
|
+
const priority = _nullishCoalesce(resolved.priority, () => ( 0));
|
|
2802
|
+
const upgraded = !recorded || !fixed && priority > recorded.priority;
|
|
2803
|
+
const carried = upgraded ? { priority, lane } : { priority: recorded.priority, lane: recorded.lane };
|
|
2804
|
+
const entry = correlated.get(resolved.target) || {
|
|
2805
|
+
source: resolved.source,
|
|
2806
|
+
priority: carried.priority,
|
|
2807
|
+
lane: carried.lane,
|
|
2808
|
+
upgraded,
|
|
2809
|
+
missed: !recorded,
|
|
2810
|
+
handler: reaction.handler.name,
|
|
2811
|
+
correlated_at: void 0
|
|
2812
|
+
};
|
|
2813
|
+
const seen_in_scan = correlated.has(resolved.target);
|
|
2814
|
+
const held_lane = _nullishCoalesce((seen_in_scan ? entry.lane : _optionalChain([recorded, 'optionalAccess', _141 => _141.lane])), () => ( _chunkBCA423WPcjs.DEFAULT_LANE));
|
|
2815
|
+
const held_priority = seen_in_scan ? entry.priority : _optionalChain([recorded, 'optionalAccess', _142 => _142.priority]);
|
|
2816
|
+
const resolved_lane = _nullishCoalesce(lane, () => ( _chunkBCA423WPcjs.DEFAULT_LANE));
|
|
2817
|
+
if (held_priority === priority && held_lane !== resolved_lane)
|
|
2818
|
+
report_lane_conflict(
|
|
2819
|
+
this._reported,
|
|
2820
|
+
reaction.handler.name,
|
|
2821
|
+
resolved.target,
|
|
2822
|
+
held_lane,
|
|
2823
|
+
resolved_lane
|
|
2824
|
+
);
|
|
2825
|
+
if (carried.priority > entry.priority) {
|
|
2826
|
+
entry.priority = carried.priority;
|
|
2827
|
+
entry.lane = carried.lane;
|
|
2828
|
+
entry.upgraded = upgraded;
|
|
2829
|
+
entry.handler = reaction.handler.name;
|
|
2830
|
+
}
|
|
2831
|
+
if (this._in_fetch_window(resolved.source, event.stream))
|
|
2832
|
+
entry.correlated_at = event.id;
|
|
2833
|
+
correlated.set(resolved.target, entry);
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
last_id = event.id;
|
|
2837
|
+
},
|
|
2838
|
+
// Resolvers see `pii: null`: correlate runs actor-less, and one
|
|
2839
|
+
// undecryptable row would otherwise stop every stream's reactions.
|
|
2840
|
+
{ after, limit, with_pii: false }
|
|
2841
|
+
);
|
|
2842
|
+
if (this._declared_lanes.size > 1) await this._recall(correlated);
|
|
2843
|
+
const read = last_id > after;
|
|
2844
|
+
if (this._epoch !== epoch) return idle();
|
|
2845
|
+
const streams = [];
|
|
2846
|
+
for (const [stream, entry] of correlated) {
|
|
2847
|
+
if (entry.upgraded || entry.correlated_at !== void 0)
|
|
2848
|
+
streams.push({
|
|
2849
|
+
stream,
|
|
2850
|
+
source: entry.source,
|
|
2851
|
+
priority: entry.priority,
|
|
2852
|
+
lane: entry.lane,
|
|
2853
|
+
correlated_at: entry.correlated_at
|
|
2854
|
+
});
|
|
2855
|
+
}
|
|
2856
|
+
if (streams.length) {
|
|
2857
|
+
const renewed_at = Date.now();
|
|
2858
|
+
const { subscribed, correlating } = await this._cd.subscribe(
|
|
2859
|
+
streams,
|
|
2860
|
+
last_id,
|
|
2861
|
+
lease ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
|
|
2862
|
+
);
|
|
2863
|
+
if (lease && correlating !== false)
|
|
2864
|
+
this._lease_until = renewed_at + CORRELATION_LEASE_MS;
|
|
2865
|
+
const marked = streams.filter(
|
|
2866
|
+
(entry) => entry.correlated_at !== void 0
|
|
2867
|
+
).length;
|
|
2868
|
+
this._checkpoint = last_id;
|
|
2869
|
+
for (const { stream, priority, lane } of streams) {
|
|
2870
|
+
if (_optionalChain([correlated, 'access', _143 => _143.get, 'call', _144 => _144(stream), 'optionalAccess', _145 => _145.upgraded]))
|
|
2871
|
+
this._dynamic_subscriptions.set(stream, {
|
|
2872
|
+
priority,
|
|
2873
|
+
lane
|
|
2874
|
+
});
|
|
2476
2875
|
}
|
|
2876
|
+
return { kind: "scanned", last_id, subscribed, marked, read };
|
|
2877
|
+
}
|
|
2878
|
+
this._checkpoint = last_id;
|
|
2879
|
+
if (!stopped && found !== limit) this._lowered = raised;
|
|
2880
|
+
return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
|
|
2881
|
+
}
|
|
2882
|
+
// Read the row of each target this scan had no record of (new or evicted),
|
|
2883
|
+
// so a resolution that doesn't beat its priority keeps the row's lane.
|
|
2884
|
+
// Only called with more than one lane declared.
|
|
2885
|
+
async _recall(correlated) {
|
|
2886
|
+
const missed = [...correlated].filter(([, entry]) => entry.missed);
|
|
2887
|
+
await Promise.all(
|
|
2888
|
+
missed.map(async ([stream, entry]) => {
|
|
2889
|
+
let row;
|
|
2890
|
+
await _chunk4UWU5FANcjs.store.call(void 0, ).query_streams(
|
|
2891
|
+
(position) => {
|
|
2892
|
+
row = position;
|
|
2893
|
+
},
|
|
2894
|
+
{ stream, stream_exact: true, limit: 1 }
|
|
2895
|
+
);
|
|
2896
|
+
if (!row) return;
|
|
2897
|
+
this._dynamic_subscriptions.set(stream, {
|
|
2898
|
+
priority: row.priority,
|
|
2899
|
+
lane: row.lane
|
|
2900
|
+
});
|
|
2901
|
+
if (entry.priority > row.priority) return;
|
|
2902
|
+
const held_lane = _nullishCoalesce(row.lane, () => ( _chunkBCA423WPcjs.DEFAULT_LANE));
|
|
2903
|
+
const resolved_lane = _nullishCoalesce(entry.lane, () => ( _chunkBCA423WPcjs.DEFAULT_LANE));
|
|
2904
|
+
if (entry.priority === row.priority && held_lane !== resolved_lane)
|
|
2905
|
+
report_lane_conflict(
|
|
2906
|
+
this._reported,
|
|
2907
|
+
entry.handler,
|
|
2908
|
+
stream,
|
|
2909
|
+
held_lane,
|
|
2910
|
+
resolved_lane
|
|
2911
|
+
);
|
|
2912
|
+
entry.priority = row.priority;
|
|
2913
|
+
entry.lane = row.lane;
|
|
2914
|
+
entry.upgraded = false;
|
|
2915
|
+
})
|
|
2477
2916
|
);
|
|
2478
|
-
this._inflight = pass;
|
|
2479
|
-
return pass;
|
|
2480
2917
|
}
|
|
2481
|
-
|
|
2482
|
-
async
|
|
2918
|
+
/** Release the lease early by re-acquiring it for zero ms. Best-effort. */
|
|
2919
|
+
async release_correlation() {
|
|
2483
2920
|
try {
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
leading,
|
|
2491
|
-
eventLimit,
|
|
2492
|
-
leaseMillis,
|
|
2493
|
-
misrouted: this._misrouted,
|
|
2494
|
-
store_failing: this._deps.breaker.failing
|
|
2921
|
+
this._lease_until = 0;
|
|
2922
|
+
this._epoch++;
|
|
2923
|
+
await this._cd.subscribe([], void 0, {
|
|
2924
|
+
key: this._key,
|
|
2925
|
+
by: this._by,
|
|
2926
|
+
millis: 0
|
|
2495
2927
|
});
|
|
2496
|
-
if (!cycle) {
|
|
2497
|
-
this._defer.prune(started);
|
|
2498
|
-
this._deps.breaker.passed();
|
|
2499
|
-
this._lowered = raised;
|
|
2500
|
-
return EMPTY_DRAIN;
|
|
2501
|
-
}
|
|
2502
|
-
const { leased, fetched, handled, acked, blocked, closeable } = cycle;
|
|
2503
|
-
trace_cycle(this._deps.logger, leased, fetched, handled, acked, blocked);
|
|
2504
|
-
this._ratio = compute_lag_lead_ratio(handled, lagging, leading);
|
|
2505
|
-
for (const lease of acked) this._defer.delete(lease.stream);
|
|
2506
|
-
for (const lease of blocked) this._defer.delete(lease.stream);
|
|
2507
|
-
for (const h of handled) {
|
|
2508
|
-
const next = _nullishCoalesce(h.defer, () => ( h.next_attempt_at));
|
|
2509
|
-
if (next !== void 0) this._defer.set(h.lease.stream, next);
|
|
2510
|
-
}
|
|
2511
|
-
if (acked.length) this._deps.on_acked(acked);
|
|
2512
|
-
if (closeable.length) await this._deps.on_close(closeable);
|
|
2513
|
-
this._deps.breaker.passed();
|
|
2514
|
-
return { fetched, leased, acked, blocked };
|
|
2515
2928
|
} catch (error) {
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
Date.now() + Math.max(leaseMillis, this._deps.breaker.cooldown_ms)
|
|
2929
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).warn(
|
|
2930
|
+
`Could not hand back the correlation lease during shutdown; it expires on its own within ${CORRELATION_LEASE_MS}ms and correlation resumes normally after that. On a single-writer store this usually means another connection holds the database. Cause: ${String(_nullishCoalesce(error.cause, () => ( error)))}`
|
|
2519
2931
|
);
|
|
2520
|
-
this._deps.breaker.failed(Date.now(), error);
|
|
2521
|
-
return EMPTY_DRAIN;
|
|
2522
|
-
} finally {
|
|
2523
|
-
if (!this._stopped) this._defer.schedule();
|
|
2524
2932
|
}
|
|
2525
2933
|
}
|
|
2526
2934
|
}, _class5);
|
|
@@ -2542,7 +2950,7 @@ function pii_gate(event, fields, predicate, actor) {
|
|
|
2542
2950
|
const { pii, ...rest } = event;
|
|
2543
2951
|
if (pii == null) {
|
|
2544
2952
|
const shredded = { ...data };
|
|
2545
|
-
for (const f of fields) shredded[f] =
|
|
2953
|
+
for (const f of fields) shredded[f] = _chunkBCA423WPcjs.SHREDDED;
|
|
2546
2954
|
return { ...rest, data: shredded };
|
|
2547
2955
|
}
|
|
2548
2956
|
const allowed = !!actor && !!predicate && predicate(event, actor);
|
|
@@ -2553,7 +2961,7 @@ function pii_gate(event, fields, predicate, actor) {
|
|
|
2553
2961
|
};
|
|
2554
2962
|
}
|
|
2555
2963
|
const redacted = { ...data };
|
|
2556
|
-
for (const f of fields) redacted[f] =
|
|
2964
|
+
for (const f of fields) redacted[f] = _chunkBCA423WPcjs.REDACTED;
|
|
2557
2965
|
return { ...rest, data: redacted };
|
|
2558
2966
|
}
|
|
2559
2967
|
var IDENTITY_GATE = (event) => event;
|
|
@@ -2631,209 +3039,33 @@ function make_fold_handler(me, flush, config2, sensitive_fields) {
|
|
|
2631
3039
|
}
|
|
2632
3040
|
const contiguous = event.version === fold.version + 1;
|
|
2633
3041
|
if (event.id > fold.event_id && !contiguous) {
|
|
2634
|
-
cache2.delete(stream);
|
|
2635
|
-
fold = await first_sight(stream);
|
|
2636
|
-
}
|
|
2637
|
-
if (event.id > fold.event_id) {
|
|
2638
|
-
const reducer = me.patch[event.name];
|
|
2639
|
-
fold.state = bare_patch(
|
|
2640
|
-
me,
|
|
2641
|
-
fold.state,
|
|
2642
|
-
reducer(event, fold.state),
|
|
2643
|
-
event
|
|
2644
|
-
);
|
|
2645
|
-
fold.version = event.version;
|
|
2646
|
-
fold.event_id = event.id;
|
|
2647
|
-
fold.patches++;
|
|
2648
|
-
fold.dirty = true;
|
|
2649
|
-
} else {
|
|
2650
|
-
fold.dirty = true;
|
|
2651
|
-
}
|
|
2652
|
-
if (++folded_since_flush >= config2.flushEvery) {
|
|
2653
|
-
await flush_dirty();
|
|
2654
|
-
folded_since_flush = 0;
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
await flush_dirty();
|
|
2658
|
-
};
|
|
2659
|
-
Object.defineProperty(handler, FOLD_RESET, { value: () => cache2.clear() });
|
|
2660
|
-
return handler;
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
// src/internal/defer-config.ts
|
|
2664
|
-
|
|
2665
|
-
var DeferDurationSchema = _zod.z.object({
|
|
2666
|
-
days: _zod.z.number().positive().optional(),
|
|
2667
|
-
hours: _zod.z.number().positive().optional(),
|
|
2668
|
-
minutes: _zod.z.number().positive().optional()
|
|
2669
|
-
}).strict().refine((d) => d.days != null || d.hours != null || d.minutes != null, {
|
|
2670
|
-
message: "defer: a duration needs at least one of days, hours, or minutes"
|
|
2671
|
-
});
|
|
2672
|
-
var DeferWhenSchema = _zod.z.object({
|
|
2673
|
-
after: DeferDurationSchema.optional(),
|
|
2674
|
-
at: _zod.z.date().optional()
|
|
2675
|
-
}).strict().refine((w) => w.after === void 0 !== (w.at === void 0), {
|
|
2676
|
-
message: "defer: specify exactly one of `after` or `at`"
|
|
2677
|
-
});
|
|
2678
|
-
function duration_ms(d) {
|
|
2679
|
-
return (_nullishCoalesce(d.days, () => ( 0))) * 864e5 + (_nullishCoalesce(d.hours, () => ( 0))) * 36e5 + (_nullishCoalesce(d.minutes, () => ( 0))) * 6e4;
|
|
2680
|
-
}
|
|
2681
|
-
function resolve_defer_at(when, event) {
|
|
2682
|
-
const parsed = DeferWhenSchema.parse(when);
|
|
2683
|
-
if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);
|
|
2684
|
-
return parsed.at.getTime();
|
|
2685
|
-
}
|
|
2686
|
-
function assert_defer_when(when) {
|
|
2687
|
-
DeferWhenSchema.parse(when);
|
|
2688
|
-
}
|
|
2689
|
-
function make_deferred(handler, schedule) {
|
|
2690
|
-
const call = handler;
|
|
2691
|
-
const deferred = async (event, stream, app) => {
|
|
2692
|
-
const when = typeof schedule === "function" ? schedule(event) : schedule;
|
|
2693
|
-
if (Date.now() < resolve_defer_at(when, event)) throw new (0, _chunkH6KVPVP4cjs.DeferSignal)(when);
|
|
2694
|
-
return call(event, stream, app);
|
|
2695
|
-
};
|
|
2696
|
-
Object.defineProperty(deferred, "name", { value: handler.name });
|
|
2697
|
-
return deferred;
|
|
2698
|
-
}
|
|
2699
|
-
|
|
2700
|
-
// src/internal/reaction-dispatch.ts
|
|
2701
|
-
var CloseSignal = class extends Error {
|
|
2702
|
-
/**
|
|
2703
|
-
* Stream to close. Omitted → the reaction's own lease stream (a self-close).
|
|
2704
|
-
* The synthesized autoclose reaction sets it to the aggregate stream, since
|
|
2705
|
-
* its lease runs on a synthetic `__autoclose__` target.
|
|
2706
|
-
*/
|
|
2707
|
-
|
|
2708
|
-
/** Optional archive callback to run while the stream is guarded. */
|
|
2709
|
-
|
|
2710
|
-
/**
|
|
2711
|
-
* Watermark to ack the requesting reaction to before the close runs. The
|
|
2712
|
-
* close-cycle safety guard skips a stream whose subscriptions (matched by
|
|
2713
|
-
* source) lag the head; the autoclose reaction's `source` is the aggregate,
|
|
2714
|
-
* so it must advance its own watermark to the live head id it evaluated
|
|
2715
|
-
* against — otherwise it blocks its own close. Defaults to the triggering
|
|
2716
|
-
* event id when omitted.
|
|
2717
|
-
*/
|
|
2718
|
-
|
|
2719
|
-
/**
|
|
2720
|
-
* Windowed close: prune events older than this cutoff behind
|
|
2721
|
-
* the closest safe snapshot instead of retiring the stream. Thrown by
|
|
2722
|
-
* the autoclose reaction of a `.autocloses({ keep })` state; flows
|
|
2723
|
-
* into {@link CloseTarget.before}. Omitted → a full close.
|
|
2724
|
-
*/
|
|
2725
|
-
|
|
2726
|
-
constructor(opts) {
|
|
2727
|
-
super("reaction requested close");
|
|
2728
|
-
this.name = "CloseSignal";
|
|
2729
|
-
this.stream = _optionalChain([opts, 'optionalAccess', _124 => _124.stream]);
|
|
2730
|
-
this.archive = _optionalChain([opts, 'optionalAccess', _125 => _125.archive]);
|
|
2731
|
-
this.at = _optionalChain([opts, 'optionalAccess', _126 => _126.at]);
|
|
2732
|
-
this.before = _optionalChain([opts, 'optionalAccess', _127 => _127.before]);
|
|
2733
|
-
}
|
|
2734
|
-
};
|
|
2735
|
-
function build_handle(deps) {
|
|
2736
|
-
const { logger, reaction_scope } = deps;
|
|
2737
|
-
return async (lease, payloads) => {
|
|
2738
|
-
if (payloads.length === 0) return { lease, handled: 0, acked_at: lease.at };
|
|
2739
|
-
const stream = lease.stream;
|
|
2740
|
-
const last_index_of = /* @__PURE__ */ new Map();
|
|
2741
|
-
for (let i = 0; i < payloads.length; i++)
|
|
2742
|
-
last_index_of.set(payloads[i].event.id, i);
|
|
2743
|
-
let at = lease.at;
|
|
2744
|
-
let handled = 0;
|
|
2745
|
-
if (lease.retry > 0)
|
|
2746
|
-
logger.warn(
|
|
2747
|
-
`Retrying ${stream}@${payloads.at(0).event.id} (${lease.retry}).`
|
|
2748
|
-
);
|
|
2749
|
-
for (let i = 0; i < payloads.length; i++) {
|
|
2750
|
-
const payload = payloads[i];
|
|
2751
|
-
const { event, handler } = payload;
|
|
2752
|
-
try {
|
|
2753
|
-
await reaction_scope.run(
|
|
2754
|
-
event,
|
|
2755
|
-
() => handler(event, stream, reaction_scope.app)
|
|
2756
|
-
);
|
|
2757
|
-
if (last_index_of.get(event.id) === i) {
|
|
2758
|
-
at = event.id;
|
|
2759
|
-
handled++;
|
|
2760
|
-
}
|
|
2761
|
-
} catch (error) {
|
|
2762
|
-
if (error instanceof _chunkH6KVPVP4cjs.DeferSignal) {
|
|
2763
|
-
let defer;
|
|
2764
|
-
try {
|
|
2765
|
-
defer = resolve_defer_at(error.when, event);
|
|
2766
|
-
} catch (invalid) {
|
|
2767
|
-
return finalize(
|
|
2768
|
-
lease,
|
|
2769
|
-
handled,
|
|
2770
|
-
at,
|
|
2771
|
-
invalid,
|
|
2772
|
-
payload.options,
|
|
2773
|
-
logger,
|
|
2774
|
-
event.id
|
|
2775
|
-
);
|
|
2776
|
-
}
|
|
2777
|
-
return { lease, handled, acked_at: at, defer };
|
|
2778
|
-
}
|
|
2779
|
-
if (error instanceof CloseSignal)
|
|
2780
|
-
return {
|
|
2781
|
-
lease,
|
|
2782
|
-
handled: handled + 1,
|
|
2783
|
-
// Advance to the live head the handler evaluated against (when
|
|
2784
|
-
// provided) so the close-cycle guard sees this reaction caught up.
|
|
2785
|
-
acked_at: _nullishCoalesce(error.at, () => ( event.id)),
|
|
2786
|
-
// Close the signalled stream (the autoclose reaction's aggregate,
|
|
2787
|
-
// which differs from its synthetic lease stream); a self-closing
|
|
2788
|
-
// user reaction omits it and closes its own lease stream. A
|
|
2789
|
-
// carried `before` makes it a windowed close (prune, not retire).
|
|
2790
|
-
close: {
|
|
2791
|
-
stream: _nullishCoalesce(error.stream, () => ( stream)),
|
|
2792
|
-
archive: error.archive,
|
|
2793
|
-
before: error.before
|
|
2794
|
-
}
|
|
2795
|
-
};
|
|
2796
|
-
return finalize(
|
|
2797
|
-
lease,
|
|
2798
|
-
handled,
|
|
2799
|
-
at,
|
|
2800
|
-
error,
|
|
2801
|
-
payload.options,
|
|
2802
|
-
logger,
|
|
2803
|
-
event.id
|
|
3042
|
+
cache2.delete(stream);
|
|
3043
|
+
fold = await first_sight(stream);
|
|
3044
|
+
}
|
|
3045
|
+
if (event.id > fold.event_id) {
|
|
3046
|
+
const reducer = me.patch[event.name];
|
|
3047
|
+
fold.state = bare_patch(
|
|
3048
|
+
me,
|
|
3049
|
+
fold.state,
|
|
3050
|
+
reducer(event, fold.state),
|
|
3051
|
+
event
|
|
2804
3052
|
);
|
|
3053
|
+
fold.version = event.version;
|
|
3054
|
+
fold.event_id = event.id;
|
|
3055
|
+
fold.patches++;
|
|
3056
|
+
fold.dirty = true;
|
|
3057
|
+
} else {
|
|
3058
|
+
fold.dirty = true;
|
|
3059
|
+
}
|
|
3060
|
+
if (++folded_since_flush >= config2.flushEvery) {
|
|
3061
|
+
await flush_dirty();
|
|
3062
|
+
folded_since_flush = 0;
|
|
2805
3063
|
}
|
|
2806
3064
|
}
|
|
2807
|
-
|
|
2808
|
-
};
|
|
2809
|
-
}
|
|
2810
|
-
function build_handle_batch(logger) {
|
|
2811
|
-
return async (lease, payloads, batchHandler) => {
|
|
2812
|
-
const stream = lease.stream;
|
|
2813
|
-
const events = [];
|
|
2814
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2815
|
-
for (const p of payloads) {
|
|
2816
|
-
if (seen.has(p.event.id)) continue;
|
|
2817
|
-
seen.add(p.event.id);
|
|
2818
|
-
events.push(p.event);
|
|
2819
|
-
}
|
|
2820
|
-
const options = payloads[0].options;
|
|
2821
|
-
if (lease.retry > 0)
|
|
2822
|
-
logger.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);
|
|
2823
|
-
try {
|
|
2824
|
-
await batchHandler(events, stream);
|
|
2825
|
-
return finalize(
|
|
2826
|
-
lease,
|
|
2827
|
-
events.length,
|
|
2828
|
-
events.at(-1).id,
|
|
2829
|
-
void 0,
|
|
2830
|
-
options,
|
|
2831
|
-
logger
|
|
2832
|
-
);
|
|
2833
|
-
} catch (error) {
|
|
2834
|
-
return finalize(lease, 0, lease.at, error, options, logger);
|
|
2835
|
-
}
|
|
3065
|
+
await flush_dirty();
|
|
2836
3066
|
};
|
|
3067
|
+
Object.defineProperty(handler, FOLD_RESET, { value: () => cache2.clear() });
|
|
3068
|
+
return handler;
|
|
2837
3069
|
}
|
|
2838
3070
|
|
|
2839
3071
|
// src/internal/settle.ts
|
|
@@ -2874,7 +3106,7 @@ var SettleLoop = (_class6 = class {
|
|
|
2874
3106
|
this._pending = true;
|
|
2875
3107
|
return;
|
|
2876
3108
|
}
|
|
2877
|
-
const delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3109
|
+
const delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _146 => _146.debounceMs]), () => ( this._default_debounce_ms));
|
|
2878
3110
|
const due = Date.now() + delay;
|
|
2879
3111
|
if (this._timer) {
|
|
2880
3112
|
if (due >= this._due) return;
|
|
@@ -3031,7 +3263,7 @@ var Act = (_class7 = class {
|
|
|
3031
3263
|
// Lanes to arm per event; `"all"` when a dynamic resolver hides the lane.
|
|
3032
3264
|
|
|
3033
3265
|
|
|
3034
|
-
__init27() {this._logger =
|
|
3266
|
+
__init27() {this._logger = _chunk4UWU5FANcjs.log.call(void 0, )}
|
|
3035
3267
|
// This Act's ports: its own bag, or the singleton adapters.
|
|
3036
3268
|
|
|
3037
3269
|
// Runs a body so internal `store()`/`cache()` calls resolve to `_ports`.
|
|
@@ -3053,9 +3285,9 @@ var Act = (_class7 = class {
|
|
|
3053
3285
|
this._lanes = lanes;
|
|
3054
3286
|
this._declared_lanes = ["default", ...lanes.map((l) => l.name)];
|
|
3055
3287
|
validate_only_lanes(options.onlyLanes, this._declared_lanes);
|
|
3056
|
-
this._ports = _nullishCoalesce(options.scoped, () => (
|
|
3288
|
+
this._ports = _nullishCoalesce(options.scoped, () => ( _chunk4UWU5FANcjs.default_scope.call(void 0, )));
|
|
3057
3289
|
const ports = this._ports;
|
|
3058
|
-
this._scoped =
|
|
3290
|
+
this._scoped = _chunk4UWU5FANcjs.make_run_scoped.call(void 0, {
|
|
3059
3291
|
// Getters, not a spread: the singletons resolve lazily, so a later
|
|
3060
3292
|
// `store(...)` / `cache(...)` still takes effect.
|
|
3061
3293
|
get store() {
|
|
@@ -3065,14 +3297,14 @@ var Act = (_class7 = class {
|
|
|
3065
3297
|
return ports.cache;
|
|
3066
3298
|
},
|
|
3067
3299
|
// Parsed per build, so a bad window throws on every build.
|
|
3068
|
-
autoclose_window:
|
|
3300
|
+
autoclose_window: _chunk4UWU5FANcjs.resolveAutocloseConfig.call(void 0, options).autocloseWindow
|
|
3069
3301
|
});
|
|
3070
3302
|
this._correlator = _nullishCoalesce(options.correlator, () => ( default_correlator));
|
|
3071
3303
|
this._es = build_es(this._logger, this._correlator, patch_fn);
|
|
3072
3304
|
this._cd = build_drain(this._logger);
|
|
3073
3305
|
const handle = build_handle({
|
|
3074
3306
|
logger: this._logger,
|
|
3075
|
-
reaction_scope:
|
|
3307
|
+
reaction_scope: _chunk4UWU5FANcjs.make_reaction_scope.call(void 0, {
|
|
3076
3308
|
do: this.do.bind(this),
|
|
3077
3309
|
load: this.load.bind(this),
|
|
3078
3310
|
query: this.query.bind(this),
|
|
@@ -3102,12 +3334,12 @@ var Act = (_class7 = class {
|
|
|
3102
3334
|
this._ports.store,
|
|
3103
3335
|
options.listen !== false
|
|
3104
3336
|
);
|
|
3105
|
-
|
|
3337
|
+
_chunk4UWU5FANcjs.register_weak_disposer.call(void 0, new WeakRef(this), (self) => self.shutdown());
|
|
3106
3338
|
}
|
|
3107
3339
|
// Shared by drain, settle and autoclose; bad knobs throw at build.
|
|
3108
3340
|
_build_breaker(options) {
|
|
3109
3341
|
return new CircuitBreaker(
|
|
3110
|
-
|
|
3342
|
+
_chunk4UWU5FANcjs.resolveCircuitBreakerConfig.call(void 0, options.circuitBreaker),
|
|
3111
3343
|
{
|
|
3112
3344
|
on_error: (error, circuit) => this._emit_error(error, circuit),
|
|
3113
3345
|
// When the cooldown elapses, settle once: its scan or claim is the
|
|
@@ -3119,7 +3351,7 @@ var Act = (_class7 = class {
|
|
|
3119
3351
|
// Apps that declare no lanes pass no lane filter to `claim`.
|
|
3120
3352
|
_build_drain_controllers(options, lanes, handle, handle_batch) {
|
|
3121
3353
|
const all_lanes = this._declared_lanes;
|
|
3122
|
-
const only_set = _optionalChain([options, 'access',
|
|
3354
|
+
const only_set = _optionalChain([options, 'access', _147 => _147.onlyLanes, 'optionalAccess', _148 => _148.length]) ? new Set(options.onlyLanes) : void 0;
|
|
3123
3355
|
const active_lanes = only_set ? all_lanes.filter((n) => only_set.has(n)) : all_lanes;
|
|
3124
3356
|
const single_default_lane = lanes.length === 0;
|
|
3125
3357
|
const controllers = /* @__PURE__ */ new Map();
|
|
@@ -3141,7 +3373,7 @@ var Act = (_class7 = class {
|
|
|
3141
3373
|
try {
|
|
3142
3374
|
await this._run_close(targets);
|
|
3143
3375
|
} catch (error) {
|
|
3144
|
-
if (error instanceof
|
|
3376
|
+
if (error instanceof _chunkBCA423WPcjs.StoreError) throw error;
|
|
3145
3377
|
this._logger.error(
|
|
3146
3378
|
error,
|
|
3147
3379
|
`Reaction-requested close of ${targets.map((t) => `"${t.stream}"`).join(", ")} failed and was not retried; close it with app.close(...) once the cause is fixed.`
|
|
@@ -3156,7 +3388,7 @@ var Act = (_class7 = class {
|
|
|
3156
3388
|
leaseMillis: cfg.leaseMillis
|
|
3157
3389
|
}
|
|
3158
3390
|
});
|
|
3159
|
-
if (_optionalChain([cfg, 'optionalAccess',
|
|
3391
|
+
if (_optionalChain([cfg, 'optionalAccess', _149 => _149.cycleMs]) !== void 0 && this._drain)
|
|
3160
3392
|
controller.start(cfg.cycleMs);
|
|
3161
3393
|
controllers.set(name, controller);
|
|
3162
3394
|
}
|
|
@@ -3175,7 +3407,7 @@ var Act = (_class7 = class {
|
|
|
3175
3407
|
// Audit deps, built after the controllers so the lane set is final.
|
|
3176
3408
|
_build_audit_deps() {
|
|
3177
3409
|
return {
|
|
3178
|
-
store:
|
|
3410
|
+
store: _chunk4UWU5FANcjs.store,
|
|
3179
3411
|
event_to_state: this._event_to_state,
|
|
3180
3412
|
// Declared lanes, not this process's controllers: a lane another
|
|
3181
3413
|
// worker drains is not `unknown-lane`.
|
|
@@ -3188,7 +3420,7 @@ var Act = (_class7 = class {
|
|
|
3188
3420
|
registry: this.registry,
|
|
3189
3421
|
static_targets: classification.static_targets,
|
|
3190
3422
|
cd: this._cd,
|
|
3191
|
-
max_subscribed_streams: _nullishCoalesce(options.maxSubscribedStreams, () => (
|
|
3423
|
+
max_subscribed_streams: _nullishCoalesce(options.maxSubscribedStreams, () => ( _chunkBCA423WPcjs.DEFAULT_MAX_SUBSCRIBED_STREAMS)),
|
|
3192
3424
|
// Declared lanes (not active ones): a lane another process claims is
|
|
3193
3425
|
// still a valid destination.
|
|
3194
3426
|
declared_lanes: new Set(this._declared_lanes),
|
|
@@ -3204,10 +3436,10 @@ var Act = (_class7 = class {
|
|
|
3204
3436
|
// Cold start: an idle deferred stream still fires on time after a restart.
|
|
3205
3437
|
async _seed_persisted_defers() {
|
|
3206
3438
|
const now = Date.now();
|
|
3207
|
-
await walk_streams(
|
|
3439
|
+
await walk_streams(_chunk4UWU5FANcjs.store.call(void 0, ), (pos) => {
|
|
3208
3440
|
if (pos.deferred_at === void 0 || pos.deferred_at <= now) return;
|
|
3209
3441
|
const controller = this._drain_controllers.get(_nullishCoalesce(pos.lane, () => ( "default")));
|
|
3210
|
-
_optionalChain([controller, 'optionalAccess',
|
|
3442
|
+
_optionalChain([controller, 'optionalAccess', _150 => _150.seed_defer, 'call', _151 => _151(pos.stream, pos.deferred_at)]);
|
|
3211
3443
|
});
|
|
3212
3444
|
}
|
|
3213
3445
|
_build_settle(options) {
|
|
@@ -3220,7 +3452,7 @@ var Act = (_class7 = class {
|
|
|
3220
3452
|
on_settled: (drain) => this.emit("settled", drain),
|
|
3221
3453
|
breaker: this._breaker
|
|
3222
3454
|
},
|
|
3223
|
-
_nullishCoalesce(options.settleDebounceMs, () => (
|
|
3455
|
+
_nullishCoalesce(options.settleDebounceMs, () => ( _chunkBCA423WPcjs.DEFAULT_SETTLE_DEBOUNCE_MS))
|
|
3224
3456
|
);
|
|
3225
3457
|
}
|
|
3226
3458
|
|
|
@@ -3240,7 +3472,7 @@ var Act = (_class7 = class {
|
|
|
3240
3472
|
*/
|
|
3241
3473
|
shutdown(options) {
|
|
3242
3474
|
if (!this._shutdown_promise) {
|
|
3243
|
-
|
|
3475
|
+
_chunk4UWU5FANcjs.resolveShutdownConfig.call(void 0, options);
|
|
3244
3476
|
this._shutdown_promise = (async () => {
|
|
3245
3477
|
this.stop_correlations();
|
|
3246
3478
|
this._settle.stop(true);
|
|
@@ -3248,7 +3480,7 @@ var Act = (_class7 = class {
|
|
|
3248
3480
|
for (const c of this._drain_controllers.values()) c.stop();
|
|
3249
3481
|
const disposer = await this._notify_disposer;
|
|
3250
3482
|
if (disposer) await disposer();
|
|
3251
|
-
await this._await_inflight(_optionalChain([options, 'optionalAccess',
|
|
3483
|
+
await this._await_inflight(_optionalChain([options, 'optionalAccess', _152 => _152.graceMs]));
|
|
3252
3484
|
await this._scoped(() => this._correlate.release_correlation());
|
|
3253
3485
|
this._emitter.removeAllListeners();
|
|
3254
3486
|
})();
|
|
@@ -3258,10 +3490,10 @@ var Act = (_class7 = class {
|
|
|
3258
3490
|
// The largest `leaseMillis` among lanes with a cycle in flight (the
|
|
3259
3491
|
// default for none or 0, and for a running settle), capped.
|
|
3260
3492
|
_derive_grace_ms(running, settling) {
|
|
3261
|
-
let max = settling ?
|
|
3493
|
+
let max = settling ? _chunk4UWU5FANcjs.DEFAULT_LEASE_MILLIS : 0;
|
|
3262
3494
|
for (const c of running)
|
|
3263
|
-
max = Math.max(max, c.lease_millis ||
|
|
3264
|
-
return Math.min(max,
|
|
3495
|
+
max = Math.max(max, c.lease_millis || _chunk4UWU5FANcjs.DEFAULT_LEASE_MILLIS);
|
|
3496
|
+
return Math.min(max, _chunk4UWU5FANcjs.MAX_SHUTDOWN_GRACE_MS);
|
|
3265
3497
|
}
|
|
3266
3498
|
async _await_inflight(grace_ms) {
|
|
3267
3499
|
const running = [...this._drain_controllers.values()].filter(
|
|
@@ -3344,8 +3576,8 @@ var Act = (_class7 = class {
|
|
|
3344
3576
|
* @see {@link ValidationError}, {@link PreconditionError}, {@link ConcurrencyError}
|
|
3345
3577
|
*/
|
|
3346
3578
|
async do(action2, target, payload, options) {
|
|
3347
|
-
const reacting_to = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3348
|
-
const do_options = reacting_to === _optionalChain([options, 'optionalAccess',
|
|
3579
|
+
const reacting_to = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _153 => _153.reactingTo]), () => ( _chunk4UWU5FANcjs.current_reacting.call(void 0, )));
|
|
3580
|
+
const do_options = reacting_to === _optionalChain([options, 'optionalAccess', _154 => _154.reactingTo]) ? options : { ...options, reactingTo: reacting_to };
|
|
3349
3581
|
return this._scoped(async () => {
|
|
3350
3582
|
const snapshots = await this._es.action(
|
|
3351
3583
|
this.registry.actions[action2],
|
|
@@ -3410,11 +3642,11 @@ var Act = (_class7 = class {
|
|
|
3410
3642
|
return this._scoped(async () => {
|
|
3411
3643
|
let first;
|
|
3412
3644
|
let last;
|
|
3413
|
-
const count = await
|
|
3645
|
+
const count = await _chunk4UWU5FANcjs.store.call(void 0, ).query((e) => {
|
|
3414
3646
|
const gated = this.registry.query_gate(e.name)(e);
|
|
3415
3647
|
if (!first) first = gated;
|
|
3416
3648
|
last = gated;
|
|
3417
|
-
_optionalChain([callback, 'optionalCall',
|
|
3649
|
+
_optionalChain([callback, 'optionalCall', _155 => _155(gated)]);
|
|
3418
3650
|
}, query);
|
|
3419
3651
|
return { first, last, count };
|
|
3420
3652
|
});
|
|
@@ -3440,7 +3672,7 @@ var Act = (_class7 = class {
|
|
|
3440
3672
|
async query_array(query) {
|
|
3441
3673
|
return this._scoped(async () => {
|
|
3442
3674
|
const events = [];
|
|
3443
|
-
await
|
|
3675
|
+
await _chunk4UWU5FANcjs.store.call(void 0, ).query((e) => {
|
|
3444
3676
|
events.push(this.registry.query_gate(e.name)(e));
|
|
3445
3677
|
}, query);
|
|
3446
3678
|
return events;
|
|
@@ -3460,14 +3692,14 @@ var Act = (_class7 = class {
|
|
|
3460
3692
|
*/
|
|
3461
3693
|
async forget(stream) {
|
|
3462
3694
|
return this._scoped(async () => {
|
|
3463
|
-
const s =
|
|
3695
|
+
const s = _chunk4UWU5FANcjs.store.call(void 0, );
|
|
3464
3696
|
if (!s.forget_pii) {
|
|
3465
3697
|
throw new Error(
|
|
3466
3698
|
`Store does not implement forget_pii \u2014 adapter cannot comply with sensitive-data erasure. Use an adapter that declares pii_isolation: true (e.g. @rotorsoft/act on the in-memory store).`
|
|
3467
3699
|
);
|
|
3468
3700
|
}
|
|
3469
3701
|
const eventCount = await s.forget_pii(stream);
|
|
3470
|
-
await
|
|
3702
|
+
await _chunk4UWU5FANcjs.cache.call(void 0, ).invalidate(stream);
|
|
3471
3703
|
if (eventCount > 0) {
|
|
3472
3704
|
this.emit("forgotten", { stream, at: /* @__PURE__ */ new Date(), eventCount });
|
|
3473
3705
|
}
|
|
@@ -3501,7 +3733,7 @@ var Act = (_class7 = class {
|
|
|
3501
3733
|
* @see {@link correlate} for dynamic stream discovery
|
|
3502
3734
|
*/
|
|
3503
3735
|
async drain(options = {}) {
|
|
3504
|
-
|
|
3736
|
+
_chunk4UWU5FANcjs.resolveDrainConfig.call(void 0, options);
|
|
3505
3737
|
if (!this._drain)
|
|
3506
3738
|
return { fetched: [], leased: [], acked: [], blocked: [] };
|
|
3507
3739
|
return this._scoped(() => this._drain_all(options));
|
|
@@ -3539,7 +3771,7 @@ var Act = (_class7 = class {
|
|
|
3539
3771
|
}
|
|
3540
3772
|
if (to_arm.size === 0) return false;
|
|
3541
3773
|
this._correlate.arm();
|
|
3542
|
-
for (const lane of to_arm) _optionalChain([this, 'access',
|
|
3774
|
+
for (const lane of to_arm) _optionalChain([this, 'access', _156 => _156._drain_controllers, 'access', _157 => _157.get, 'call', _158 => _158(lane), 'optionalAccess', _159 => _159.arm, 'call', _160 => _160()]);
|
|
3543
3775
|
return true;
|
|
3544
3776
|
}
|
|
3545
3777
|
// In parallel, so a slow lane never holds up a fast one.
|
|
@@ -3681,9 +3913,9 @@ var Act = (_class7 = class {
|
|
|
3681
3913
|
*/
|
|
3682
3914
|
async reset(input) {
|
|
3683
3915
|
return this._scoped(async () => {
|
|
3684
|
-
const count = await
|
|
3916
|
+
const count = await _chunk4UWU5FANcjs.store.call(void 0, ).reset(input);
|
|
3685
3917
|
for (const handler of this._batch_handlers.values())
|
|
3686
|
-
_optionalChain([handler, 'access',
|
|
3918
|
+
_optionalChain([handler, 'access', _161 => _161[FOLD_RESET], 'optionalCall', _162 => _162()]);
|
|
3687
3919
|
if (count > 0) {
|
|
3688
3920
|
this._wake();
|
|
3689
3921
|
}
|
|
@@ -3717,7 +3949,7 @@ var Act = (_class7 = class {
|
|
|
3717
3949
|
*/
|
|
3718
3950
|
async unblock(input) {
|
|
3719
3951
|
return this._scoped(async () => {
|
|
3720
|
-
const count = await
|
|
3952
|
+
const count = await _chunk4UWU5FANcjs.store.call(void 0, ).unblock(input);
|
|
3721
3953
|
if (count > 0) {
|
|
3722
3954
|
this._wake();
|
|
3723
3955
|
}
|
|
@@ -3772,7 +4004,7 @@ var Act = (_class7 = class {
|
|
|
3772
4004
|
return { ...partial, duration_ms: Date.now() - started };
|
|
3773
4005
|
}
|
|
3774
4006
|
const target = _nullishCoalesce(sink, () => ( (() => {
|
|
3775
|
-
const s =
|
|
4007
|
+
const s = _chunk4UWU5FANcjs.store.call(void 0, );
|
|
3776
4008
|
if (!s.restore) throw new Error("adapter has no restore capability");
|
|
3777
4009
|
return s;
|
|
3778
4010
|
})()));
|
|
@@ -3818,11 +4050,11 @@ var Act = (_class7 = class {
|
|
|
3818
4050
|
async blocked_streams(options) {
|
|
3819
4051
|
return this._scoped(async () => {
|
|
3820
4052
|
const positions = [];
|
|
3821
|
-
await
|
|
4053
|
+
await _chunk4UWU5FANcjs.store.call(void 0, ).query_streams(
|
|
3822
4054
|
(p) => {
|
|
3823
4055
|
positions.push(p);
|
|
3824
4056
|
},
|
|
3825
|
-
{ blocked: true, after: _optionalChain([options, 'optionalAccess',
|
|
4057
|
+
{ blocked: true, after: _optionalChain([options, 'optionalAccess', _163 => _163.after]), limit: _optionalChain([options, 'optionalAccess', _164 => _164.limit]) }
|
|
3826
4058
|
);
|
|
3827
4059
|
return positions;
|
|
3828
4060
|
});
|
|
@@ -3870,7 +4102,7 @@ var Act = (_class7 = class {
|
|
|
3870
4102
|
* @see {@link Store.prioritize} for the underlying primitive
|
|
3871
4103
|
*/
|
|
3872
4104
|
async prioritize(filter, priority) {
|
|
3873
|
-
return this._scoped(() =>
|
|
4105
|
+
return this._scoped(() => _chunk4UWU5FANcjs.store.call(void 0, ).prioritize(filter, priority));
|
|
3874
4106
|
}
|
|
3875
4107
|
// Shared by `close()` and reaction-requested closes.
|
|
3876
4108
|
async _run_close(targets) {
|
|
@@ -3950,219 +4182,11 @@ var Act = (_class7 = class {
|
|
|
3950
4182
|
* @see {@link correlate} for manual correlation
|
|
3951
4183
|
*/
|
|
3952
4184
|
settle(options) {
|
|
3953
|
-
|
|
4185
|
+
_chunk4UWU5FANcjs.resolveSettleConfig.call(void 0, _nullishCoalesce(options, () => ( {})));
|
|
3954
4186
|
this._schedule(options);
|
|
3955
4187
|
}
|
|
3956
4188
|
}, _class7);
|
|
3957
4189
|
|
|
3958
|
-
// src/internal/autoclose-policy.ts
|
|
3959
|
-
|
|
3960
|
-
var DAY_MS = 864e5;
|
|
3961
|
-
var MIN_AFTER_DAYS = 1 / 1440;
|
|
3962
|
-
var MIN_KEEP_DAYS = 1;
|
|
3963
|
-
function days_after(date, days) {
|
|
3964
|
-
return new Date(date.getTime() + days * DAY_MS);
|
|
3965
|
-
}
|
|
3966
|
-
function days_before_now(days) {
|
|
3967
|
-
return new Date(Date.now() - days * DAY_MS);
|
|
3968
|
-
}
|
|
3969
|
-
var window_schema = (field, min_days, floor) => _zod.z.object({
|
|
3970
|
-
days: _zod.z.number({ message: `autocloses: ${field}.days must be a number` }).positive(`autocloses: ${field}.days must be > 0`)
|
|
3971
|
-
}).refine((o) => o.days >= min_days, {
|
|
3972
|
-
message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`
|
|
3973
|
-
});
|
|
3974
|
-
var AfterSchema = window_schema("after", MIN_AFTER_DAYS, "one minute");
|
|
3975
|
-
var KeepSchema = window_schema("keep", MIN_KEEP_DAYS, "one day");
|
|
3976
|
-
var IsSchema = _zod.z.union([
|
|
3977
|
-
_zod.z.string().min(1, "autocloses: is must be a non-empty event name"),
|
|
3978
|
-
_zod.z.array(
|
|
3979
|
-
_zod.z.string().min(1, "autocloses: is entries must be non-empty event names")
|
|
3980
|
-
).min(1, "autocloses: is must include at least one event name").readonly()
|
|
3981
|
-
]);
|
|
3982
|
-
var ReachesSchema = _zod.z.number({ message: "autocloses: reaches must be a number" }).int("autocloses: reaches must be an integer").min(1, "autocloses: reaches must be >= 1");
|
|
3983
|
-
var OrBlockSchema = _zod.z.object({
|
|
3984
|
-
after: AfterSchema.optional(),
|
|
3985
|
-
is: IsSchema.optional(),
|
|
3986
|
-
reaches: ReachesSchema.optional()
|
|
3987
|
-
}).strict().refine(
|
|
3988
|
-
(o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0,
|
|
3989
|
-
{
|
|
3990
|
-
message: "autocloses: `or` block must include at least one of after / is / reaches"
|
|
3991
|
-
}
|
|
3992
|
-
);
|
|
3993
|
-
var AutoclosePolicySchema = _zod.z.object({
|
|
3994
|
-
after: AfterSchema.optional(),
|
|
3995
|
-
is: IsSchema.optional(),
|
|
3996
|
-
reaches: ReachesSchema.optional(),
|
|
3997
|
-
or: OrBlockSchema.optional(),
|
|
3998
|
-
keep: KeepSchema.optional()
|
|
3999
|
-
}).strict().refine(
|
|
4000
|
-
(o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0 || o.or !== void 0 || o.keep !== void 0,
|
|
4001
|
-
{
|
|
4002
|
-
message: "autocloses: at least one of after / is / reaches / or / keep must be specified \u2014 empty `{}` is a misconfiguration"
|
|
4003
|
-
}
|
|
4004
|
-
);
|
|
4005
|
-
function compile_after(after) {
|
|
4006
|
-
return (_stream, head) => days_after(head.created, after.days) <= /* @__PURE__ */ new Date();
|
|
4007
|
-
}
|
|
4008
|
-
function compile_is(is) {
|
|
4009
|
-
const set = new Set(typeof is === "string" ? [is] : is);
|
|
4010
|
-
return (_stream, head) => set.has(head.name);
|
|
4011
|
-
}
|
|
4012
|
-
function compile_reaches(reaches) {
|
|
4013
|
-
return (_stream, _head, count) => count >= reaches;
|
|
4014
|
-
}
|
|
4015
|
-
function policy_min_after_days(options) {
|
|
4016
|
-
const parsed = AutoclosePolicySchema.parse(options);
|
|
4017
|
-
const windows = [];
|
|
4018
|
-
if (parsed.after) windows.push(parsed.after.days);
|
|
4019
|
-
if (_optionalChain([parsed, 'access', _147 => _147.or, 'optionalAccess', _148 => _148.after])) windows.push(parsed.or.after.days);
|
|
4020
|
-
return windows.length ? Math.min(...windows) : void 0;
|
|
4021
|
-
}
|
|
4022
|
-
function policy_after_windows(options) {
|
|
4023
|
-
const parsed = AutoclosePolicySchema.parse(options);
|
|
4024
|
-
return [parsed.after, _optionalChain([parsed, 'access', _149 => _149.or, 'optionalAccess', _150 => _150.after])].flatMap((w) => w ? [w.days] : []);
|
|
4025
|
-
}
|
|
4026
|
-
function policy_keep_days(options) {
|
|
4027
|
-
const parsed = AutoclosePolicySchema.parse(options);
|
|
4028
|
-
return _optionalChain([parsed, 'access', _151 => _151.keep, 'optionalAccess', _152 => _152.days]);
|
|
4029
|
-
}
|
|
4030
|
-
function compile_autoclose_policy(options) {
|
|
4031
|
-
const parsed = AutoclosePolicySchema.parse(options);
|
|
4032
|
-
const and_preds = [];
|
|
4033
|
-
if (parsed.after) and_preds.push(compile_after(parsed.after));
|
|
4034
|
-
if (parsed.is) and_preds.push(compile_is(parsed.is));
|
|
4035
|
-
if (parsed.reaches) and_preds.push(compile_reaches(parsed.reaches));
|
|
4036
|
-
const or_preds = [];
|
|
4037
|
-
if (parsed.or) {
|
|
4038
|
-
if (parsed.or.after) or_preds.push(compile_after(parsed.or.after));
|
|
4039
|
-
if (parsed.or.is) or_preds.push(compile_is(parsed.or.is));
|
|
4040
|
-
if (parsed.or.reaches) or_preds.push(compile_reaches(parsed.or.reaches));
|
|
4041
|
-
}
|
|
4042
|
-
return (stream, head, count) => {
|
|
4043
|
-
if (and_preds.length > 0 && and_preds.every((p) => p(stream, head, count))) {
|
|
4044
|
-
return true;
|
|
4045
|
-
}
|
|
4046
|
-
if (or_preds.some((p) => p(stream, head, count))) {
|
|
4047
|
-
return true;
|
|
4048
|
-
}
|
|
4049
|
-
return false;
|
|
4050
|
-
};
|
|
4051
|
-
}
|
|
4052
|
-
|
|
4053
|
-
// src/internal/autoclose-window.ts
|
|
4054
|
-
function hour_in_zone(now, timeZone) {
|
|
4055
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
4056
|
-
timeZone,
|
|
4057
|
-
hour: "2-digit",
|
|
4058
|
-
hourCycle: "h23"
|
|
4059
|
-
}).formatToParts(now);
|
|
4060
|
-
return Number(_optionalChain([parts, 'access', _153 => _153.find, 'call', _154 => _154((p) => p.type === "hour"), 'optionalAccess', _155 => _155.value]));
|
|
4061
|
-
}
|
|
4062
|
-
function hour_in_range(hour, start, end) {
|
|
4063
|
-
return start < end ? hour >= start && hour < end : hour >= start || hour < end;
|
|
4064
|
-
}
|
|
4065
|
-
function is_dst_gap_open(now, timeZone, start) {
|
|
4066
|
-
const hour = hour_in_zone(now, timeZone);
|
|
4067
|
-
if (hour <= start) return false;
|
|
4068
|
-
const prev = hour_in_zone(new Date(now.getTime() - 36e5), timeZone);
|
|
4069
|
-
return prev === start - 1 && hour === start + 1;
|
|
4070
|
-
}
|
|
4071
|
-
function in_autoclose_window(window, now) {
|
|
4072
|
-
if (!window) return true;
|
|
4073
|
-
const hour = hour_in_zone(now, window.timeZone);
|
|
4074
|
-
return hour_in_range(hour, window.start, window.end) || is_dst_gap_open(now, window.timeZone, window.start);
|
|
4075
|
-
}
|
|
4076
|
-
function next_window_open(window, now) {
|
|
4077
|
-
const start_ms = now.getTime();
|
|
4078
|
-
for (let h = 0; h <= 48; h++) {
|
|
4079
|
-
const candidate = new Date(start_ms + h * 36e5);
|
|
4080
|
-
if (hour_in_zone(candidate, window.timeZone) === window.start)
|
|
4081
|
-
return candidate;
|
|
4082
|
-
const boundary = new Date(
|
|
4083
|
-
candidate.getTime() - candidate.getTime() % 36e5
|
|
4084
|
-
);
|
|
4085
|
-
if (boundary.getTime() >= start_ms && is_dst_gap_open(boundary, window.timeZone, window.start))
|
|
4086
|
-
return boundary;
|
|
4087
|
-
}
|
|
4088
|
-
return new Date(start_ms + 864e5);
|
|
4089
|
-
}
|
|
4090
|
-
|
|
4091
|
-
// src/internal/autoclose-reaction.ts
|
|
4092
|
-
var AUTOCLOSE_TARGET_PREFIX = "__autoclose__:";
|
|
4093
|
-
function synthesize_autoclose_reactions(registry, states, read_window) {
|
|
4094
|
-
for (const st of states.values()) {
|
|
4095
|
-
const predicate = st.autoclose;
|
|
4096
|
-
if (!predicate) continue;
|
|
4097
|
-
const after_windows = st.autoclose_after_windows;
|
|
4098
|
-
const keep_days = st.autoclose_keep_days;
|
|
4099
|
-
const archiver = st.archive;
|
|
4100
|
-
const reaction = {
|
|
4101
|
-
// Run on a SYNTHETIC stream — `source` is the aggregate, `target` is a
|
|
4102
|
-
// per-aggregate `__autoclose__` key — so the autoclose reaction never
|
|
4103
|
-
// shares a watermark with the aggregate's own reactions. A shared
|
|
4104
|
-
// watermark would let autoclose's defer short-circuit the aggregate's
|
|
4105
|
-
// other reactions (the "a defer affects all reactions on a stream"
|
|
4106
|
-
// hazard). The close still targets the aggregate (`source`).
|
|
4107
|
-
resolver: (e) => ({
|
|
4108
|
-
target: `${AUTOCLOSE_TARGET_PREFIX}${e.stream}`,
|
|
4109
|
-
source: e.stream
|
|
4110
|
-
}),
|
|
4111
|
-
// Never block on autoclose: a transient query/store error should retry,
|
|
4112
|
-
// not quarantine the synthetic stream.
|
|
4113
|
-
options: { blockOnError: false, maxRetries: _chunkPRDX3HP6cjs.DEFAULT_MAX_RETRIES },
|
|
4114
|
-
handler: async (event) => {
|
|
4115
|
-
const aggregate = event.stream;
|
|
4116
|
-
const window = read_window();
|
|
4117
|
-
if (!in_autoclose_window(window, /* @__PURE__ */ new Date()))
|
|
4118
|
-
throw new (0, _chunkH6KVPVP4cjs.DeferSignal)({ at: next_window_open(window, /* @__PURE__ */ new Date()) });
|
|
4119
|
-
const stats = await _chunkPRDX3HP6cjs.store.call(void 0, ).query_stats([aggregate], {
|
|
4120
|
-
count: true,
|
|
4121
|
-
tail: keep_days !== void 0 ? true : void 0,
|
|
4122
|
-
exclude: [_chunkH6KVPVP4cjs.TOMBSTONE_EVENT, _chunkH6KVPVP4cjs.SNAP_EVENT]
|
|
4123
|
-
});
|
|
4124
|
-
const entry = stats.get(aggregate);
|
|
4125
|
-
if (!entry) return;
|
|
4126
|
-
const head = entry.head;
|
|
4127
|
-
if (predicate(aggregate, head, entry.count))
|
|
4128
|
-
throw new CloseSignal({
|
|
4129
|
-
stream: aggregate,
|
|
4130
|
-
archive: archiver ? () => archiver(aggregate, head) : void 0,
|
|
4131
|
-
// Ack this reaction's own watermark to the live head so the
|
|
4132
|
-
// close-cycle guard (which matches subscriptions by source =
|
|
4133
|
-
// aggregate) sees it caught up instead of blocking its own close.
|
|
4134
|
-
at: head.id
|
|
4135
|
-
});
|
|
4136
|
-
if (keep_days !== void 0) {
|
|
4137
|
-
const cutoff = days_before_now(keep_days);
|
|
4138
|
-
if (entry.tail.created < cutoff)
|
|
4139
|
-
throw new CloseSignal({
|
|
4140
|
-
stream: aggregate,
|
|
4141
|
-
before: cutoff,
|
|
4142
|
-
archive: archiver ? () => archiver(aggregate, head, cutoff) : void 0,
|
|
4143
|
-
at: head.id
|
|
4144
|
-
});
|
|
4145
|
-
}
|
|
4146
|
-
const dues = [];
|
|
4147
|
-
for (const days of after_windows)
|
|
4148
|
-
dues.push(days_after(head.created, days));
|
|
4149
|
-
if (keep_days !== void 0)
|
|
4150
|
-
dues.push(days_after(entry.tail.created, keep_days));
|
|
4151
|
-
const future = dues.map((d) => d.getTime()).filter((t) => t > Date.now());
|
|
4152
|
-
if (future.length)
|
|
4153
|
-
throw new (0, _chunkH6KVPVP4cjs.DeferSignal)({ at: new Date(Math.min(...future)) });
|
|
4154
|
-
}
|
|
4155
|
-
};
|
|
4156
|
-
const key = `__autoclose_${st.name}`;
|
|
4157
|
-
for (const event_name of Object.keys(st.events)) {
|
|
4158
|
-
_optionalChain([registry, 'access', _156 => _156.events, 'access', _157 => _157[event_name], 'optionalAccess', _158 => _158.reactions, 'access', _159 => _159.set, 'call', _160 => _160(
|
|
4159
|
-
key,
|
|
4160
|
-
reaction
|
|
4161
|
-
)]);
|
|
4162
|
-
}
|
|
4163
|
-
}
|
|
4164
|
-
}
|
|
4165
|
-
|
|
4166
4190
|
// src/builders/merge.ts
|
|
4167
4191
|
|
|
4168
4192
|
function base_type_name(zodType) {
|
|
@@ -4356,9 +4380,9 @@ var _this_ = ({ stream }) => ({
|
|
|
4356
4380
|
|
|
4357
4381
|
// src/builders/builder-utils.ts
|
|
4358
4382
|
function register_lane(config2, lanes) {
|
|
4359
|
-
|
|
4360
|
-
if (config2.name ===
|
|
4361
|
-
throw new Error(`Lane "${
|
|
4383
|
+
_chunk4UWU5FANcjs.resolveLaneConfig.call(void 0, config2);
|
|
4384
|
+
if (config2.name === _chunkBCA423WPcjs.DEFAULT_LANE)
|
|
4385
|
+
throw new Error(`Lane "${_chunkBCA423WPcjs.DEFAULT_LANE}" is reserved`);
|
|
4362
4386
|
const existing = lanes.find((l) => l.name === config2.name);
|
|
4363
4387
|
if (!existing) return void lanes.push(config2);
|
|
4364
4388
|
if (existing.leaseMillis !== config2.leaseMillis || existing.streamLimit !== config2.streamLimit || existing.cycleMs !== config2.cycleMs)
|
|
@@ -4400,10 +4424,10 @@ function reaction_on(event, events, builder) {
|
|
|
4400
4424
|
// Validate the whole bag at the declaration site so a bad
|
|
4401
4425
|
// `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,
|
|
4402
4426
|
// not a NaN gate on the first retry.
|
|
4403
|
-
options:
|
|
4404
|
-
blockOnError: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
4405
|
-
maxRetries: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
4406
|
-
backoff: _optionalChain([options, 'optionalAccess',
|
|
4427
|
+
options: _chunk4UWU5FANcjs.resolveReactionConfig.call(void 0, {
|
|
4428
|
+
blockOnError: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _165 => _165.blockOnError]), () => ( _chunk4UWU5FANcjs.DEFAULT_BLOCK_ON_ERROR)),
|
|
4429
|
+
maxRetries: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _166 => _166.maxRetries]), () => ( _chunk4UWU5FANcjs.DEFAULT_MAX_RETRIES)),
|
|
4430
|
+
backoff: _optionalChain([options, 'optionalAccess', _167 => _167.backoff])
|
|
4407
4431
|
})
|
|
4408
4432
|
};
|
|
4409
4433
|
},
|
|
@@ -4422,25 +4446,47 @@ function reaction_on(event, events, builder) {
|
|
|
4422
4446
|
|
|
4423
4447
|
// src/internal/date-reviver.ts
|
|
4424
4448
|
|
|
4425
|
-
function variant_schema(schema) {
|
|
4426
|
-
const shape = _optionalChain([
|
|
4449
|
+
function variant_schema(schema, walk) {
|
|
4450
|
+
const shape = _optionalChain([_chunkBCA423WPcjs.def_of.call(void 0, schema), 'optionalAccess', _168 => _168.shape]);
|
|
4427
4451
|
if (!shape) {
|
|
4428
|
-
const dates =
|
|
4452
|
+
const dates = walk(schema);
|
|
4429
4453
|
return { schema: _nullishCoalesce(dates, () => ( schema)), dated: !!dates };
|
|
4430
4454
|
}
|
|
4431
4455
|
const next = {};
|
|
4432
4456
|
let dated = false;
|
|
4433
4457
|
for (const [key, field] of Object.entries(shape)) {
|
|
4434
|
-
const dates =
|
|
4458
|
+
const dates = walk(field);
|
|
4435
4459
|
if (dates) dated = true;
|
|
4436
4460
|
next[key] = (_nullishCoalesce(dates, () => ( field))).optional();
|
|
4437
4461
|
}
|
|
4438
4462
|
return { schema: _zod.z.looseObject(next), dated };
|
|
4439
4463
|
}
|
|
4440
4464
|
function date_reviver_schema(schema) {
|
|
4441
|
-
|
|
4465
|
+
let recursive = false;
|
|
4466
|
+
const pass = (tie) => {
|
|
4467
|
+
const done = /* @__PURE__ */ new Map();
|
|
4468
|
+
const active = /* @__PURE__ */ new Set();
|
|
4469
|
+
const walk = (node) => {
|
|
4470
|
+
if (done.has(node)) return done.get(node);
|
|
4471
|
+
if (active.has(node)) {
|
|
4472
|
+
recursive = true;
|
|
4473
|
+
return tie ? _zod.z.lazy(() => done.get(node)) : void 0;
|
|
4474
|
+
}
|
|
4475
|
+
active.add(node);
|
|
4476
|
+
const result = build(node, walk);
|
|
4477
|
+
active.delete(node);
|
|
4478
|
+
done.set(node, result);
|
|
4479
|
+
return result;
|
|
4480
|
+
};
|
|
4481
|
+
return walk(schema);
|
|
4482
|
+
};
|
|
4483
|
+
const first = pass(false);
|
|
4484
|
+
return first && recursive ? pass(true) : first;
|
|
4485
|
+
}
|
|
4486
|
+
function build(schema, walk) {
|
|
4487
|
+
const def = _chunkBCA423WPcjs.def_of.call(void 0, schema);
|
|
4442
4488
|
if (!def) return void 0;
|
|
4443
|
-
const inner = () =>
|
|
4489
|
+
const inner = () => walk(def.innerType);
|
|
4444
4490
|
switch (def.type) {
|
|
4445
4491
|
case "date":
|
|
4446
4492
|
return _zod.z.coerce.date();
|
|
@@ -4449,39 +4495,48 @@ function date_reviver_schema(schema) {
|
|
|
4449
4495
|
if (!shape) return void 0;
|
|
4450
4496
|
const dated = {};
|
|
4451
4497
|
for (const [key, field] of Object.entries(shape)) {
|
|
4452
|
-
const dates =
|
|
4498
|
+
const dates = walk(field);
|
|
4453
4499
|
if (dates) dated[key] = dates.optional();
|
|
4454
4500
|
}
|
|
4455
4501
|
return Object.keys(dated).length ? _zod.z.looseObject(dated) : void 0;
|
|
4456
4502
|
}
|
|
4457
4503
|
case "array": {
|
|
4458
|
-
const element =
|
|
4504
|
+
const element = walk(def.element);
|
|
4459
4505
|
return element && _zod.z.array(element);
|
|
4460
4506
|
}
|
|
4461
4507
|
case "tuple": {
|
|
4462
|
-
const items = def.items.map((i) =>
|
|
4508
|
+
const items = def.items.map((i) => walk(i));
|
|
4463
4509
|
return items.some(Boolean) ? _zod.z.tuple(items.map((i) => _nullishCoalesce(i, () => ( _zod.z.unknown())))) : void 0;
|
|
4464
4510
|
}
|
|
4465
4511
|
case "record": {
|
|
4466
|
-
const value =
|
|
4512
|
+
const value = walk(def.valueType);
|
|
4467
4513
|
return value && _zod.z.record(_zod.z.string(), value);
|
|
4468
4514
|
}
|
|
4469
4515
|
case "union": {
|
|
4470
|
-
const variants = def.options.map(
|
|
4516
|
+
const variants = def.options.map(
|
|
4517
|
+
(o) => variant_schema(o, walk)
|
|
4518
|
+
);
|
|
4471
4519
|
return variants.some((v) => v.dated) ? _zod.z.union(variants.map((v) => v.schema)) : void 0;
|
|
4472
4520
|
}
|
|
4473
4521
|
case "nullable":
|
|
4474
|
-
return _optionalChain([inner, 'call',
|
|
4522
|
+
return _optionalChain([inner, 'call', _169 => _169(), 'optionalAccess', _170 => _170.nullable, 'call', _171 => _171()]);
|
|
4475
4523
|
case "pipe":
|
|
4476
|
-
return
|
|
4524
|
+
return walk(def.out);
|
|
4525
|
+
case "lazy":
|
|
4526
|
+
return walk(def.getter());
|
|
4527
|
+
case "intersection": {
|
|
4528
|
+
const left = walk(def.left);
|
|
4529
|
+
const right = walk(def.right);
|
|
4530
|
+
return left && right ? left.pipe(right) : _nullishCoalesce(left, () => ( right));
|
|
4531
|
+
}
|
|
4477
4532
|
default:
|
|
4478
|
-
return
|
|
4533
|
+
return _chunkBCA423WPcjs.inner_of.call(void 0, def) ? inner() : void 0;
|
|
4479
4534
|
}
|
|
4480
4535
|
}
|
|
4481
4536
|
|
|
4482
4537
|
// src/builders/event-builder.ts
|
|
4483
4538
|
function event_tags(schema) {
|
|
4484
|
-
const pii =
|
|
4539
|
+
const pii = _chunkBCA423WPcjs.pii_schemas.call(void 0, schema);
|
|
4485
4540
|
const pii_dates = {};
|
|
4486
4541
|
for (const [key, field] of Object.entries(pii)) {
|
|
4487
4542
|
const dates = date_reviver_schema(field);
|
|
@@ -4519,7 +4574,7 @@ function make_event_reader(tags, disclosure, predicate = null) {
|
|
|
4519
4574
|
});
|
|
4520
4575
|
}
|
|
4521
4576
|
function build_events(registry, states, lanes, owners) {
|
|
4522
|
-
const declared = /* @__PURE__ */ new Set([
|
|
4577
|
+
const declared = /* @__PURE__ */ new Set([_chunkBCA423WPcjs.DEFAULT_LANE, ...lanes.map((l) => l.name)]);
|
|
4523
4578
|
const lane_errors = [];
|
|
4524
4579
|
const tags = /* @__PURE__ */ new Map();
|
|
4525
4580
|
const sensitive2 = /* @__PURE__ */ new Map();
|
|
@@ -4594,7 +4649,7 @@ function build_events(registry, states, lanes, owners) {
|
|
|
4594
4649
|
if (reader) readers.set(event_name, reader);
|
|
4595
4650
|
}
|
|
4596
4651
|
const snap2 = make_event_reader(event_tags(state2.state), "redact", null);
|
|
4597
|
-
if (snap2) readers.set(
|
|
4652
|
+
if (snap2) readers.set(_chunkBCA423WPcjs.SNAP_EVENT, snap2);
|
|
4598
4653
|
if (readers.size === 0) continue;
|
|
4599
4654
|
state2.view = (event, actor) => (_nullishCoalesce(readers.get(event.name), () => ( IDENTITY_GATE)))(event, actor);
|
|
4600
4655
|
}
|
|
@@ -4602,7 +4657,7 @@ function build_events(registry, states, lanes, owners) {
|
|
|
4602
4657
|
return { sensitive: sensitive2, advisory, query_readers, handler_readers };
|
|
4603
4658
|
}
|
|
4604
4659
|
function reads_as_string(schema) {
|
|
4605
|
-
const type = _optionalChain([
|
|
4660
|
+
const type = _optionalChain([_chunkBCA423WPcjs.def_of.call(void 0, _chunkBCA423WPcjs.output_of.call(void 0, schema)), 'optionalAccess', _172 => _172.type]);
|
|
4606
4661
|
return type === "string" || type === "transform";
|
|
4607
4662
|
}
|
|
4608
4663
|
|
|
@@ -4660,7 +4715,7 @@ function act() {
|
|
|
4660
4715
|
let _built = false;
|
|
4661
4716
|
const read_wrap = (original) => {
|
|
4662
4717
|
const wrapped = async (events, stream) => {
|
|
4663
|
-
const read = events.map((e) => _nullishCoalesce(_optionalChain([_hr, 'access',
|
|
4718
|
+
const read = events.map((e) => _nullishCoalesce(_optionalChain([_hr, 'access', _173 => _173.get, 'call', _174 => _174(e.name), 'optionalCall', _175 => _175(e)]), () => ( e)));
|
|
4664
4719
|
return original(read, stream);
|
|
4665
4720
|
};
|
|
4666
4721
|
const reset = original[FOLD_RESET];
|
|
@@ -4701,7 +4756,7 @@ function act() {
|
|
|
4701
4756
|
});
|
|
4702
4757
|
}
|
|
4703
4758
|
for (const [action_name, handler] of Object.entries(state2.on)) {
|
|
4704
|
-
const static_target = _optionalChain([handler, 'optionalAccess',
|
|
4759
|
+
const static_target = _optionalChain([handler, 'optionalAccess', _176 => _176._static_emit]);
|
|
4705
4760
|
if (static_target && deprecated.has(static_target)) {
|
|
4706
4761
|
const current = current_version_of(static_target, event_names);
|
|
4707
4762
|
throw new Error(
|
|
@@ -4714,7 +4769,7 @@ function act() {
|
|
|
4714
4769
|
const list = deprecation_summary.map(
|
|
4715
4770
|
(d) => `"${d.deprecated}" (current: "${d.current}", state: "${d.state_name}")`
|
|
4716
4771
|
).join(", ");
|
|
4717
|
-
|
|
4772
|
+
_chunk4UWU5FANcjs.log.call(void 0, ).info(
|
|
4718
4773
|
`Act registered ${deprecation_summary.length} deprecated event(s): ${list}. These are legacy versions kept for the read path. Consider truncating closed streams via app.close() when feasible to reduce historical event load. See docs/docs/architecture/event-schema-evolution.md.`
|
|
4719
4774
|
);
|
|
4720
4775
|
}
|
|
@@ -4756,7 +4811,7 @@ function act() {
|
|
|
4756
4811
|
return reaction_on(event, registry.events, builder);
|
|
4757
4812
|
},
|
|
4758
4813
|
build: (options) => {
|
|
4759
|
-
|
|
4814
|
+
_chunk4UWU5FANcjs.resolveActConfig.call(void 0, options);
|
|
4760
4815
|
if (!_built) {
|
|
4761
4816
|
for (const proj of pending_projections) add_projection(proj);
|
|
4762
4817
|
for (const proj of fold_projections) {
|
|
@@ -4774,7 +4829,7 @@ function act() {
|
|
|
4774
4829
|
`State projection "${proj.target}" of "${fold.name}" is missing events ${missing.join(", ")} \u2014 pass every partial of the state to .of()`
|
|
4775
4830
|
);
|
|
4776
4831
|
const claimed = fold_specs.find((s) => s.target === proj.target);
|
|
4777
|
-
if (_optionalChain([claimed, 'optionalAccess',
|
|
4832
|
+
if (_optionalChain([claimed, 'optionalAccess', _177 => _177.projection]) === proj) continue;
|
|
4778
4833
|
if (batch_handlers.has(proj.target) || claimed)
|
|
4779
4834
|
throw new Error(
|
|
4780
4835
|
`Duplicate projection target "${proj.target}" \u2014 a target is served by one batch handler or one state projection, never both`
|
|
@@ -4796,7 +4851,7 @@ function act() {
|
|
|
4796
4851
|
for (const [name, gate] of built.query_readers) _qg.set(name, gate);
|
|
4797
4852
|
for (const [name, gate] of built.handler_readers) _hr.set(name, gate);
|
|
4798
4853
|
finalize_deprecations();
|
|
4799
|
-
if (built.advisory)
|
|
4854
|
+
if (built.advisory) _chunk4UWU5FANcjs.log.call(void 0, ).warn(built.advisory);
|
|
4800
4855
|
for (const state2 of states.values()) {
|
|
4801
4856
|
if (state2.disclose) _dp.set(state2.name, state2.disclose);
|
|
4802
4857
|
if (state2.autoclose) _ac.set(state2.name, state2.autoclose);
|
|
@@ -4808,7 +4863,7 @@ function act() {
|
|
|
4808
4863
|
synthesize_autoclose_reactions(
|
|
4809
4864
|
registry,
|
|
4810
4865
|
states,
|
|
4811
|
-
|
|
4866
|
+
_chunk4UWU5FANcjs.current_autoclose_window
|
|
4812
4867
|
);
|
|
4813
4868
|
Object.freeze(registry.actions);
|
|
4814
4869
|
Object.freeze(registry.events);
|
|
@@ -4856,8 +4911,8 @@ function _projection(target) {
|
|
|
4856
4911
|
handler,
|
|
4857
4912
|
resolver: _nullishCoalesce(default_resolver, () => ( _this_)),
|
|
4858
4913
|
options: {
|
|
4859
|
-
blockOnError:
|
|
4860
|
-
maxRetries:
|
|
4914
|
+
blockOnError: _chunk4UWU5FANcjs.DEFAULT_BLOCK_ON_ERROR,
|
|
4915
|
+
maxRetries: _chunk4UWU5FANcjs.DEFAULT_MAX_RETRIES
|
|
4861
4916
|
}
|
|
4862
4917
|
}),
|
|
4863
4918
|
widened
|
|
@@ -4898,7 +4953,7 @@ function _projection(target) {
|
|
|
4898
4953
|
throw new Error(
|
|
4899
4954
|
`Projection "${target}" .of() partials must share one state name \u2014 got "${name}" and "${partial.name}"`
|
|
4900
4955
|
);
|
|
4901
|
-
const config2 =
|
|
4956
|
+
const config2 = _chunk4UWU5FANcjs.resolveFoldConfig.call(void 0, options);
|
|
4902
4957
|
const fold_events = {};
|
|
4903
4958
|
for (const partial of partials)
|
|
4904
4959
|
for (const [event_name, schema] of Object.entries(partial.events)) {
|
|
@@ -4916,8 +4971,8 @@ function _projection(target) {
|
|
|
4916
4971
|
handler: noop,
|
|
4917
4972
|
resolver: { target },
|
|
4918
4973
|
options: {
|
|
4919
|
-
blockOnError:
|
|
4920
|
-
maxRetries:
|
|
4974
|
+
blockOnError: _chunk4UWU5FANcjs.DEFAULT_BLOCK_ON_ERROR,
|
|
4975
|
+
maxRetries: _chunk4UWU5FANcjs.DEFAULT_MAX_RETRIES
|
|
4921
4976
|
}
|
|
4922
4977
|
}
|
|
4923
4978
|
]
|
|
@@ -5033,7 +5088,7 @@ function action_builder(state2) {
|
|
|
5033
5088
|
throw new Error(`Duplicate action "${action2}"`);
|
|
5034
5089
|
internal.actions[action2] = schema;
|
|
5035
5090
|
if (options) {
|
|
5036
|
-
|
|
5091
|
+
_chunk4UWU5FANcjs.resolveActionConfig.call(void 0, options);
|
|
5037
5092
|
internal.options ??= {};
|
|
5038
5093
|
internal.options[action2] = options;
|
|
5039
5094
|
}
|
|
@@ -5327,5 +5382,7 @@ function write_line(writer, line) {
|
|
|
5327
5382
|
|
|
5328
5383
|
|
|
5329
5384
|
|
|
5330
|
-
|
|
5385
|
+
|
|
5386
|
+
|
|
5387
|
+
exports.Act = Act; exports.ActorSchema = _chunkBCA423WPcjs.ActorSchema; exports.CausationEventSchema = _chunkBCA423WPcjs.CausationEventSchema; exports.CommittedMetaSchema = _chunkBCA423WPcjs.CommittedMetaSchema; exports.ConcurrencyError = _chunkBCA423WPcjs.ConcurrencyError; exports.ConsoleLogger = _chunk4UWU5FANcjs.ConsoleLogger; exports.CsvFile = CsvFile; exports.DEFAULT_LANE = _chunkBCA423WPcjs.DEFAULT_LANE; exports.DEFAULT_MAX_SUBSCRIBED_STREAMS = _chunkBCA423WPcjs.DEFAULT_MAX_SUBSCRIBED_STREAMS; exports.DEFAULT_QUERY_STREAMS_LIMIT = _chunk4UWU5FANcjs.DEFAULT_QUERY_STREAMS_LIMIT; exports.DEFAULT_SETTLE_DEBOUNCE_MS = _chunkBCA423WPcjs.DEFAULT_SETTLE_DEBOUNCE_MS; exports.DeferSignal = _chunkBCA423WPcjs.DeferSignal; exports.Environments = _chunkBCA423WPcjs.Environments; exports.Errors = _chunkBCA423WPcjs.Errors; exports.EventMetaSchema = _chunkBCA423WPcjs.EventMetaSchema; exports.ExitCodes = _chunkBCA423WPcjs.ExitCodes; exports.InMemoryCache = _chunk4UWU5FANcjs.InMemoryCache; exports.InMemoryStore = _chunk4UWU5FANcjs.InMemoryStore; exports.InvariantError = _chunkBCA423WPcjs.InvariantError; exports.LogLevels = _chunkBCA423WPcjs.LogLevels; exports.NonRetryableError = _chunkBCA423WPcjs.NonRetryableError; exports.PackageSchema = _chunk4UWU5FANcjs.PackageSchema; exports.PreconditionError = _chunkBCA423WPcjs.PreconditionError; exports.QuerySchema = _chunkBCA423WPcjs.QuerySchema; exports.REDACTED = _chunkBCA423WPcjs.REDACTED; exports.SHREDDED = _chunkBCA423WPcjs.SHREDDED; exports.SNAP_EVENT = _chunkBCA423WPcjs.SNAP_EVENT; exports.StoreError = _chunkBCA423WPcjs.StoreError; exports.StreamClosedError = _chunkBCA423WPcjs.StreamClosedError; exports.TOMBSTONE_EVENT = _chunkBCA423WPcjs.TOMBSTONE_EVENT; exports.TargetSchema = _chunkBCA423WPcjs.TargetSchema; exports.ValidationError = _chunkBCA423WPcjs.ValidationError; exports.ZodEmpty = _chunkBCA423WPcjs.ZodEmpty; exports.act = act; exports.cache = _chunk4UWU5FANcjs.cache; exports.config = _chunk4UWU5FANcjs.config; exports.dateReviver = _chunk4UWU5FANcjs.dateReviver; exports.default_scope = _chunk4UWU5FANcjs.default_scope; exports.dispose = _chunk4UWU5FANcjs.dispose; exports.disposeAndExit = _chunk4UWU5FANcjs.disposeAndExit; exports.extend = _chunk4UWU5FANcjs.extend; exports.fair_slots = _chunk4UWU5FANcjs.fair_slots; exports.is_literal_source = _chunk4UWU5FANcjs.is_literal_source; exports.log = _chunk4UWU5FANcjs.log; exports.pii_fields = _chunkBCA423WPcjs.pii_fields; exports.port = _chunk4UWU5FANcjs.port; exports.projection = projection; exports.resolveAutocloseConfig = _chunk4UWU5FANcjs.resolveAutocloseConfig2; exports.sensitive = _chunkBCA423WPcjs.sensitive; exports.sleep = _chunk4UWU5FANcjs.sleep; exports.slice = slice; exports.state = state; exports.store = _chunk4UWU5FANcjs.store; exports.validate = _chunk4UWU5FANcjs.validate;
|
|
5331
5388
|
//# sourceMappingURL=index.cjs.map
|