@rotorsoft/act 1.37.7 → 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.
Files changed (35) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
  3. package/dist/@types/internal/autoclose-reaction.d.ts +8 -0
  4. package/dist/@types/internal/autoclose-reaction.d.ts.map +1 -1
  5. package/dist/@types/internal/close-cycle.d.ts.map +1 -1
  6. package/dist/@types/internal/date-reviver.d.ts +6 -3
  7. package/dist/@types/internal/date-reviver.d.ts.map +1 -1
  8. package/dist/@types/internal/drain-ops.d.ts.map +1 -1
  9. package/dist/@types/internal/reaction-dispatch.d.ts +6 -0
  10. package/dist/@types/internal/reaction-dispatch.d.ts.map +1 -1
  11. package/dist/@types/types/ports.d.ts +5 -6
  12. package/dist/@types/types/ports.d.ts.map +1 -1
  13. package/dist/@types/utils.d.ts +18 -1
  14. package/dist/@types/utils.d.ts.map +1 -1
  15. package/dist/{chunk-PRDX3HP6.cjs → chunk-4UWU5FAN.cjs} +25 -24
  16. package/dist/chunk-4UWU5FAN.cjs.map +1 -0
  17. package/dist/{chunk-H6KVPVP4.cjs → chunk-BCA423WP.cjs} +1 -1
  18. package/dist/chunk-BCA423WP.cjs.map +1 -0
  19. package/dist/{chunk-V5ZB54DC.js → chunk-I5RF2NFR.js} +1 -1
  20. package/dist/chunk-I5RF2NFR.js.map +1 -0
  21. package/dist/{chunk-HXW3TPP6.js → chunk-TSDQDT4S.js} +13 -12
  22. package/dist/chunk-TSDQDT4S.js.map +1 -0
  23. package/dist/index.cjs +1654 -1608
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.js +1261 -1215
  26. package/dist/index.js.map +1 -1
  27. package/dist/test/index.cjs +4 -4
  28. package/dist/test/index.js +2 -2
  29. package/dist/types/index.cjs +2 -2
  30. package/dist/types/index.js +1 -1
  31. package/package.json +1 -1
  32. package/dist/chunk-H6KVPVP4.cjs.map +0 -1
  33. package/dist/chunk-HXW3TPP6.js.map +0 -1
  34. package/dist/chunk-PRDX3HP6.cjs.map +0 -1
  35. 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
- var _chunkH6KVPVP4cjs = require('./chunk-H6KVPVP4.cjs');
77
+
78
+
79
+ var _chunkBCA423WPcjs = require('./chunk-BCA423WP.cjs');
78
80
 
79
81
  // src/signals.ts
80
82
  process.once("SIGINT", async (arg) => {
81
- _chunkPRDX3HP6cjs.log.call(void 0, ).info(arg, "SIGINT");
82
- await _chunkPRDX3HP6cjs.disposeAndExit.call(void 0, "EXIT");
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
- _chunkPRDX3HP6cjs.log.call(void 0, ).info(arg, "SIGTERM");
86
- await _chunkPRDX3HP6cjs.disposeAndExit.call(void 0, "EXIT");
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
- _chunkPRDX3HP6cjs.log.call(void 0, ).error(arg, "Uncaught Exception");
90
- await _chunkPRDX3HP6cjs.disposeAndExit.call(void 0, "ERROR");
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
- _chunkPRDX3HP6cjs.log.call(void 0, ).error(arg, "Unhandled Rejection");
94
- await _chunkPRDX3HP6cjs.disposeAndExit.call(void 0, "ERROR");
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: [_chunkH6KVPVP4cjs.SNAP_EVENT] }
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 = _chunkH6KVPVP4cjs.pii_fields.call(void 0, schema);
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,7 +417,7 @@ var make_restart_candidate_pass = (deps, options) => {
415
417
  {
416
418
  stream,
417
419
  stream_exact: true,
418
- names: [_chunkH6KVPVP4cjs.SNAP_EVENT],
420
+ names: [_chunkBCA423WPcjs.SNAP_EVENT],
419
421
  with_snaps: true,
420
422
  // From the start: on its own, `with_snaps` resumes at the latest.
421
423
  after: -1
@@ -575,7 +577,7 @@ var make_correlation_gaps_pass = () => {
575
577
  seen_ids.add(e.id);
576
578
  const causation = _optionalChain([e, 'access', _31 => _31.meta, 'optionalAccess', _32 => _32.causation]);
577
579
  const parent_id = _optionalChain([causation, 'optionalAccess', _33 => _33.event, 'optionalAccess', _34 => _34.id]);
578
- if (parent_id !== void 0 && e.name !== _chunkH6KVPVP4cjs.TOMBSTONE_EVENT) {
580
+ if (parent_id !== void 0 && e.name !== _chunkBCA423WPcjs.TOMBSTONE_EVENT) {
579
581
  checks.push({ stream: e.stream, id: e.id, parent_id });
580
582
  }
581
583
  },
@@ -797,674 +799,303 @@ function classify_registry(registry, states) {
797
799
  };
798
800
  }
799
801
 
800
- // src/internal/close-cycle.ts
801
- var CLOSE_CATCH_UP_LIMIT = 1e3;
802
- var CLOSE_CATCH_UP_PASSES = 20;
803
- async function catch_up_correlation(cursor, correlate, until) {
804
- for (let pass = 0; pass < CLOSE_CATCH_UP_PASSES && cursor.checkpoint < until; pass++) {
805
- const before = cursor.checkpoint;
806
- cursor.arm();
807
- await correlate(CLOSE_CATCH_UP_LIMIT);
808
- if (cursor.checkpoint <= before) break;
809
- }
810
- 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);
811
809
  }
812
- var CloseLock = (_class2 = class {constructor() { _class2.prototype.__init2.call(this); }
813
- __init2() {this._tails = /* @__PURE__ */ new Map()}
814
- /** Run `work` after every earlier close of `stream` has settled. */
815
- run(stream, work) {
816
- const prev = _nullishCoalesce(this._tails.get(stream), () => ( Promise.resolve()));
817
- const next = prev.then(work, work);
818
- this._tails.set(stream, next);
819
- const cleanup = () => {
820
- if (this._tails.get(stream) === next) this._tails.delete(stream);
821
- };
822
- next.then(cleanup, cleanup);
823
- return next;
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"
824
835
  }
825
- }, _class2);
826
- var SAFETY_PROBE_PAGE_SIZE = 1e3;
827
- async function run_close_cycle(targets, deps) {
828
- const target_map = new Map(targets.map((t) => [t.stream, t]));
829
- for (const t of target_map.values()) {
830
- if (t.before !== void 0 && t.restart)
831
- throw new Error(
832
- `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`
833
- );
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"
834
847
  }
835
- const windowed = [...target_map.values()].filter(
836
- (t) => t.before !== void 0
837
- );
838
- const full = [...target_map.values()].filter((t) => t.before === void 0);
839
- const skipped = [];
840
- const windowed_result = windowed.length ? await run_windowed_closes(windowed, deps, skipped) : /* @__PURE__ */ new Map();
841
- if (!full.length) return { truncated: windowed_result, skipped };
842
- const truncated = await with_stream_locks(
843
- full.map((t) => t.stream),
844
- deps,
845
- () => run_full_closes(full, target_map, deps, skipped)
846
- );
847
- const retired = [...truncated.entries()].filter(([, r]) => r.committed.name === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT).map(([stream]) => stream);
848
- if (retired.length) _optionalChain([deps, 'access', _42 => _42.forget_subscribed, 'optionalCall', _43 => _43(retired)]);
849
- for (const [stream, entry] of windowed_result) truncated.set(stream, entry);
850
- return { truncated, skipped };
848
+ );
849
+ function compile_after(after) {
850
+ return (_stream, head) => days_after(head.created, after.days) <= /* @__PURE__ */ new Date();
851
851
  }
852
- function with_stream_locks(streams, deps, work) {
853
- const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, w) => w())));
854
- return [...streams].sort().reduceRight(
855
- (inner, stream) => () => with_lock(stream, inner),
856
- work
857
- )();
852
+ function compile_is(is) {
853
+ const set = new Set(typeof is === "string" ? [is] : is);
854
+ return (_stream, head) => set.has(head.name);
858
855
  }
859
- async function run_full_closes(full, target_map, deps, skipped) {
860
- const none = /* @__PURE__ */ new Map();
861
- const streams = full.map((t) => t.stream);
862
- const stream_info = await scan_stream_heads(streams);
863
- for (const target of full) {
864
- if (!target.restart) continue;
865
- const info = stream_info.get(target.stream);
866
- if (!info) continue;
867
- const owner = deps.event_to_state.get(info.last_event_name);
868
- if (_optionalChain([owner, 'optionalAccess', _44 => _44.pii_aware])) {
869
- deps.logger.error(
870
- `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.`
871
- );
872
- skipped.push(target.stream);
873
- stream_info.delete(target.stream);
874
- }
875
- }
876
- const safe = await partition_by_safety(
877
- stream_info,
878
- deps.reactive,
879
- skipped,
880
- _nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
881
- deps.catch_up_correlation
882
- );
883
- if (!safe.length) return none;
884
- const { guarded, guard_events } = await guard_with_tombstones(
885
- safe,
886
- stream_info,
887
- deps.correlation,
888
- deps.tombstone,
889
- skipped
890
- );
891
- if (!guarded.length) return none;
892
- const seed_states = await load_restart_seeds(
893
- guarded,
894
- target_map,
895
- stream_info,
896
- deps.event_to_state,
897
- deps.load,
898
- deps.logger
899
- );
900
- await run_archive_callbacks(guarded, target_map);
901
- const still_guarded = await heads_still_guarded(
902
- guarded,
903
- guard_events,
904
- skipped
905
- );
906
- if (!still_guarded.length) return none;
907
- return truncate_and_warm_cache(
908
- still_guarded,
909
- seed_states,
910
- guard_events,
911
- deps.correlation
912
- );
856
+ function compile_reaches(reaches) {
857
+ return (_stream, _head, count) => count >= reaches;
913
858
  }
914
- async function run_windowed_closes(windowed, deps, skipped) {
915
- const checkpoint = deps.reactive ? await deps.catch_up_correlation(Number.MAX_SAFE_INTEGER) : -1;
916
- const min_at = deps.reactive ? await probe_min_watermarks(
917
- windowed.map((t) => t.stream),
918
- _nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
919
- checkpoint
920
- ) : /* @__PURE__ */ new Map();
921
- const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, work) => work())));
922
- const truncated = /* @__PURE__ */ new Map();
923
- for (const t of windowed) {
924
- const entry = await with_lock(t.stream, async () => {
925
- const max_id = min_at.get(t.stream);
926
- if (!await windowed_prune_pending(t.stream, t.before, max_id))
927
- return void 0;
928
- if (t.archive) await t.archive();
929
- const result = await _chunkPRDX3HP6cjs.store.call(void 0, ).truncate([
930
- { stream: t.stream, before: t.before, max_id }
931
- ]);
932
- return result.get(t.stream);
933
- });
934
- if (entry) truncated.set(t.stream, entry);
935
- else skipped.push(t.stream);
936
- }
937
- 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;
938
865
  }
939
- async function windowed_prune_pending(stream, before, max_id) {
940
- let boundary_id;
941
- let min_id;
942
- await _chunkPRDX3HP6cjs.store.call(void 0, ).query(
943
- (event) => {
944
- if (min_id === void 0 || event.id < min_id) min_id = event.id;
945
- 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))
946
- boundary_id = event.id;
947
- },
948
- { stream, stream_exact: true, with_snaps: true, after: -1 }
949
- );
950
- 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] : []);
951
869
  }
952
- async function probe_min_watermarks(streams, page_size, checkpoint) {
953
- const min_at = /* @__PURE__ */ new Map();
954
- const matches = source_matcher();
955
- await walk_streams(
956
- _chunkPRDX3HP6cjs.store.call(void 0, ),
957
- (position) => {
958
- const pending = position.correlated_at === void 0 || position.at < position.correlated_at;
959
- const cap = pending ? position.at : Math.max(position.at, checkpoint);
960
- for (const stream of streams) {
961
- if (matches(position.source, stream)) {
962
- const prev = min_at.get(stream);
963
- if (prev === void 0 || cap < prev) min_at.set(stream, cap);
964
- }
965
- }
966
- },
967
- { limit: page_size, source_matches: streams }
968
- );
969
- 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]);
970
873
  }
971
- function source_matcher() {
972
- const compiled = /* @__PURE__ */ new Map();
973
- return (source, stream) => {
974
- if (!source) return true;
975
- let re = compiled.get(source);
976
- if (!re) {
977
- re = new RegExp(source);
978
- compiled.set(source, re);
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;
979
889
  }
980
- return re.test(stream);
890
+ if (or_preds.some((p) => p(stream, head, count))) {
891
+ return true;
892
+ }
893
+ return false;
981
894
  };
982
895
  }
983
- async function scan_stream_heads(streams) {
984
- const stats = await _chunkPRDX3HP6cjs.store.call(void 0, ).query_stats(streams, {
985
- exclude: [_chunkH6KVPVP4cjs.SNAP_EVENT]
986
- });
987
- const domain_heads = await _chunkPRDX3HP6cjs.store.call(void 0, ).query_stats(streams, {
988
- exclude: [_chunkH6KVPVP4cjs.SNAP_EVENT, _chunkH6KVPVP4cjs.TOMBSTONE_EVENT]
989
- });
990
- const true_heads = await _chunkPRDX3HP6cjs.store.call(void 0, ).query_stats(streams, {});
991
- const out = /* @__PURE__ */ new Map();
992
- for (const [stream, { head }] of domain_heads) {
993
- const marker_head = _optionalChain([stats, 'access', _45 => _45.get, 'call', _46 => _46(stream), 'optionalAccess', _47 => _47.head]);
994
- const interrupted = _optionalChain([marker_head, 'optionalAccess', _48 => _48.name]) === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT;
995
- out.set(stream, {
996
- max_id: head.id,
997
- version: true_heads.get(stream).head.version,
998
- last_event_name: head.name,
999
- ...interrupted ? { resumed_guard: { id: marker_head.id } } : {}
1000
- });
1001
- }
1002
- return out;
1003
- }
1004
- async function partition_by_safety(stream_info, reactive, skipped, page_size, catch_up_correlation2) {
1005
- if (!reactive) return [...stream_info.keys()];
1006
- let needed = -1;
1007
- for (const info of stream_info.values())
1008
- needed = Math.max(needed, info.max_id);
1009
- const checkpoint = await catch_up_correlation2(needed);
1010
- const uncorrelated = /* @__PURE__ */ new Set();
1011
- for (const [stream, info] of stream_info) {
1012
- if (checkpoint < info.max_id) uncorrelated.add(stream);
1013
- }
1014
- const pending_set = /* @__PURE__ */ new Set();
1015
- const matches = source_matcher();
1016
- const targets = [...stream_info.keys()];
1017
- await walk_streams(
1018
- _chunkPRDX3HP6cjs.store.call(void 0, ),
1019
- (position) => {
1020
- const has_work = position.correlated_at !== void 0 && position.at < position.correlated_at;
1021
- if (!has_work) return;
1022
- for (const [stream, info] of stream_info) {
1023
- if (matches(position.source, stream) && position.at < info.max_id)
1024
- pending_set.add(stream);
1025
- }
1026
- },
1027
- { limit: page_size, source_matches: targets }
1028
- );
1029
- const safe = [];
1030
- for (const [stream] of stream_info) {
1031
- if (pending_set.has(stream) || uncorrelated.has(stream))
1032
- skipped.push(stream);
1033
- else safe.push(stream);
1034
- }
1035
- 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]));
1036
905
  }
1037
- async function guard_with_tombstones(safe, stream_info, correlation, tombstone2, skipped) {
1038
- const guarded = [];
1039
- const guard_events = /* @__PURE__ */ new Map();
1040
- await Promise.all(
1041
- safe.map(async (stream) => {
1042
- const info = stream_info.get(stream);
1043
- if (info.resumed_guard) {
1044
- guarded.push(stream);
1045
- guard_events.set(stream, { id: info.resumed_guard.id, stream });
1046
- return;
1047
- }
1048
- const committed = await tombstone2(stream, info.version, correlation);
1049
- if (committed) {
1050
- guarded.push(stream);
1051
- guard_events.set(stream, { id: committed.id, stream });
1052
- } else {
1053
- skipped.push(stream);
1054
- }
1055
- })
1056
- );
1057
- return { guarded, guard_events };
906
+ function hour_in_range(hour, start, end) {
907
+ return start < end ? hour >= start && hour < end : hour >= start || hour < end;
1058
908
  }
1059
- async function load_restart_seeds(guarded, target_map, stream_info, event_to_state, load2, logger) {
1060
- const seed_states = /* @__PURE__ */ new Map();
1061
- await Promise.all(
1062
- guarded.filter((s) => _optionalChain([target_map, 'access', _49 => _49.get, 'call', _50 => _50(s), 'optionalAccess', _51 => _51.restart])).map(async (stream) => {
1063
- const last_event_name = stream_info.get(stream).last_event_name;
1064
- const owner_state = event_to_state.get(last_event_name);
1065
- if (!owner_state) {
1066
- logger.error(
1067
- `Cannot seed restart for "${stream}": no registered state owns event "${last_event_name}". Stream will be tombstoned instead.`
1068
- );
1069
- return;
1070
- }
1071
- const snap2 = await load2(owner_state, { stream });
1072
- seed_states.set(stream, snap2.state);
1073
- })
1074
- );
1075
- 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;
1076
914
  }
1077
- async function run_archive_callbacks(guarded, target_map) {
1078
- for (const stream of guarded) {
1079
- const archive_fn = _optionalChain([target_map, 'access', _52 => _52.get, 'call', _53 => _53(stream), 'optionalAccess', _54 => _54.archive]);
1080
- if (archive_fn) await archive_fn();
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;
1081
931
  }
932
+ return new Date(start_ms + 864e5);
1082
933
  }
1083
- async function heads_still_guarded(guarded, guard_events, skipped) {
1084
- const heads = await _chunkPRDX3HP6cjs.store.call(void 0, ).query_stats(guarded, {});
1085
- return guarded.filter((stream) => {
1086
- if (_optionalChain([heads, 'access', _55 => _55.get, 'call', _56 => _56(stream), 'optionalAccess', _57 => _57.head, 'access', _58 => _58.id]) === guard_events.get(stream).id)
1087
- return true;
1088
- skipped.push(stream);
1089
- return false;
1090
- });
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;
1091
952
  }
1092
- async function truncate_and_warm_cache(guarded, seed_states, guard_events, correlation) {
1093
- const trunc_targets = guarded.map((stream) => {
1094
- const snapshot = seed_states.get(stream);
1095
- const guard = guard_events.get(stream);
1096
- return {
1097
- stream,
1098
- snapshot,
1099
- meta: {
1100
- correlation,
1101
- causation: {
1102
- event: { id: guard.id, name: _chunkH6KVPVP4cjs.TOMBSTONE_EVENT, stream: guard.stream }
1103
- }
1104
- }
1105
- };
1106
- });
1107
- const truncated = await _chunkPRDX3HP6cjs.store.call(void 0, ).truncate(trunc_targets);
1108
- await Promise.all(
1109
- guarded.map(async (stream) => {
1110
- const entry = truncated.get(stream);
1111
- const state2 = seed_states.get(stream);
1112
- if (state2 && entry) {
1113
- await _chunkPRDX3HP6cjs.cache.call(void 0, ).set(stream, {
1114
- stream,
1115
- state: state2,
1116
- version: entry.committed.version,
1117
- event_id: entry.committed.id,
1118
- patches: 0,
1119
- snaps: 1
1120
- });
1121
- } else {
1122
- await _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(stream);
1123
- }
1124
- })
1125
- );
1126
- 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;
1127
970
  }
1128
971
 
1129
- // src/internal/correlate-cycle.ts
972
+ // src/internal/drain-cycle.ts
1130
973
  var _crypto = require('crypto');
1131
974
 
1132
- // src/internal/report-once.ts
1133
- function report_once(seen, key, message) {
1134
- if (seen.has(key)) return;
1135
- seen.add(key);
1136
- _chunkPRDX3HP6cjs.log.call(void 0, ).error(new Error(message));
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));
1137
998
  }
1138
999
 
1139
- // src/internal/correlate-cycle.ts
1140
- var COLD_START_BACK_SCAN = 1e4;
1141
- var CORRELATION_LEASE_MS = 5e3;
1142
- var registry_key = (events) => {
1143
- const shape = Object.keys(events).filter((name) => events[name].reactions.size > 0).sort().map((name) => [name, [...events[name].reactions.keys()].sort()]);
1144
- return _crypto.createHash.call(void 0, "sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 32);
1145
- };
1146
- var PATTERN_CACHE_SIZE = 32;
1147
- function report_undeclared_lane(seen, handler, target, lane, declared) {
1148
- report_once(
1149
- seen,
1150
- `lane|${handler}|${lane}`,
1151
- `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.`
1152
- );
1153
- }
1154
- function report_lane_conflict(seen, handler, target, kept, dropped) {
1155
- report_once(
1156
- seen,
1157
- `conflict|${handler}|${kept}|${dropped}`,
1158
- `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.`
1159
- );
1160
- }
1161
- var CorrelateCycle = (_class3 = class {
1162
- __init3() {this._checkpoint = -1}
1163
- // Lease holder id; per instance, so a restart never inherits a stale claim.
1164
- __init4() {this._by = _crypto.randomUUID.call(void 0, )}
1165
-
1166
- // Local expiry of the held lease (0 = none); stale only costs a duplicate scan.
1167
- __init5() {this._lease_until = 0}
1168
- // Armed while `_raised` (bumped by a commit or notification) is ahead of
1169
- // `_lowered` (the raise count the last short page saw). Starts armed.
1170
- __init6() {this._raised = 1}
1171
- __init7() {this._lowered = 0}
1172
- // Bumped by a release (shutdown), so a scan or lease reply that was out
1173
- // across one writes nothing.
1174
- __init8() {this._epoch = 0}
1175
- // Passes in flight: a restore waits for them, and refuses new ones.
1176
- __init9() {this._passes = /* @__PURE__ */ new Set()}
1177
- __init10() {this._restoring = false}
1178
-
1179
- // Bounded by `maxSubscribedStreams`; static records live apart so eviction
1180
- // never lets a resolution re-lane them.
1181
-
1182
- __init11() {this._static_subscriptions = /* @__PURE__ */ new Map()}
1183
- __init12() {this._patterns = new (0, _chunkPRDX3HP6cjs.LruMap)(PATTERN_CACHE_SIZE)}
1184
-
1185
-
1186
-
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()}
1187
1004
 
1188
1005
 
1189
- // Report-once keys; per instance because `internal/` holds no module state.
1190
- __init13() {this._reported = /* @__PURE__ */ new Set()}
1191
- constructor({
1192
- registry,
1193
- static_targets,
1194
- cd,
1195
- max_subscribed_streams,
1196
- declared_lanes,
1197
- shard,
1198
- on_init
1199
- }) {;_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);
1200
- this._key = shard ? `${registry_key(registry.events)}:${[...shard].sort().join(",")}` : registry_key(registry.events);
1201
- this._dynamic_subscriptions = new (0, _chunkPRDX3HP6cjs.LruMap)(max_subscribed_streams);
1202
- this._registry = registry;
1203
- this._declared_lanes = declared_lanes;
1204
- this._static_targets = static_targets;
1205
- this._cd = cd;
1206
- this._on_init = on_init;
1207
- }
1208
- get checkpoint() {
1209
- return this._checkpoint;
1210
- }
1211
- /** A commit (local or remote) may have produced uncorrelated events. */
1212
- arm() {
1213
- this._raised++;
1214
- }
1215
- async _init() {
1216
- this._init_promise ??= this._run_init().catch((error) => {
1217
- this._init_promise = void 0;
1218
- throw error;
1219
- });
1220
- await this._init_promise;
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;
1221
1012
  }
1222
- async _run_init() {
1223
- const { watermark, correlated_at } = await this._cd.subscribe([
1224
- ...this._static_targets
1225
- ]);
1226
- this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - COLD_START_BACK_SCAN);
1227
- for (const { stream, priority = 0, lane } of this._static_targets) {
1228
- this._static_subscriptions.set(stream, {
1229
- priority,
1230
- lane
1231
- });
1232
- }
1233
- await _optionalChain([this, 'access', _59 => _59._on_init, 'optionalCall', _60 => _60()]);
1013
+ /** Number of currently parked streams. */
1014
+ get size() {
1015
+ return this._due.size;
1234
1016
  }
1235
1017
  /**
1236
- * Replace the log with no pass in flight, then cold-start: a pass that
1237
- * read the old log writes before the restore, never into the new one.
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.
1238
1022
  */
1239
- async restart(restore) {
1240
- this._restoring = true;
1241
- try {
1242
- await Promise.allSettled(this._passes);
1243
- await restore();
1244
- } finally {
1245
- this._restoring = false;
1246
- }
1247
- this._init_promise = void 0;
1248
- this._checkpoint = -1;
1249
- this._dynamic_subscriptions.clear();
1250
- this._static_subscriptions.clear();
1251
- }
1252
- /** Forget dynamic targets whose rows a full close deleted, so they re-subscribe. */
1253
- forget_subscribed(streams) {
1254
- for (const stream of streams) this._dynamic_subscriptions.delete(stream);
1023
+ set(stream, at) {
1024
+ this._due.set(stream, at);
1255
1025
  }
1256
- // Would the target's own `fetch` (filtered by `source`) return this event?
1257
- _in_fetch_window(source, stream) {
1258
- if (source === void 0 || source === stream) return true;
1259
- if (_chunkPRDX3HP6cjs.is_literal_source.call(void 0, source)) return false;
1260
- let pattern = this._patterns.get(source);
1261
- if (!pattern) {
1262
- pattern = new RegExp(source);
1263
- this._patterns.set(source, pattern);
1264
- }
1265
- return pattern.test(stream);
1026
+ /** Drop `stream` from the parked set (e.g. on a successful ack or block). */
1027
+ delete(stream) {
1028
+ this._due.delete(stream);
1266
1029
  }
1267
- /** Scan past the checkpoint, subscribe new targets and raise their work marks. */
1268
- async correlate(limit, lease = false) {
1269
- if (this._restoring) return { kind: "idle", last_id: this._checkpoint };
1270
- const pass = this._scan(limit, lease);
1271
- this._passes.add(pass);
1272
- try {
1273
- return await pass;
1274
- } finally {
1275
- this._passes.delete(pass);
1276
- }
1030
+ /**
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.
1035
+ */
1036
+ prune(before) {
1037
+ for (const [stream, at] of this._due)
1038
+ if (at <= before) this._due.delete(stream);
1277
1039
  }
1278
- async _scan(limit, lease) {
1279
- await this._init();
1280
- const epoch = this._epoch;
1281
- const idle = () => ({
1282
- kind: "idle",
1283
- last_id: this._checkpoint
1284
- });
1285
- if (this._raised === this._lowered) return idle();
1286
- const raised = this._raised;
1287
- const now = Date.now();
1288
- if (lease && now >= this._lease_until - CORRELATION_LEASE_MS / 2) {
1289
- const { correlating } = await this._cd.subscribe([], void 0, {
1290
- key: this._key,
1291
- by: this._by,
1292
- millis: CORRELATION_LEASE_MS
1293
- });
1294
- if (this._epoch !== epoch) return idle();
1295
- this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
1296
- if (correlating === false) return idle();
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;
1297
1053
  }
1298
- const after = this._checkpoint;
1299
- const correlated = /* @__PURE__ */ new Map();
1300
- let last_id = after;
1301
- let stopped = false;
1302
- const found = await _chunkPRDX3HP6cjs.store.call(void 0, ).query(
1303
- (event) => {
1304
- if (stopped) return;
1305
- const register = this._registry.events[event.name];
1306
- if (register) {
1307
- for (const reaction of register.reactions.values()) {
1308
- let resolved;
1309
- try {
1310
- resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
1311
- } catch (error) {
1312
- stopped = true;
1313
- report_once(
1314
- this._reported,
1315
- `resolver|${reaction.handler.name}|${event.id}`,
1316
- `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.`
1317
- );
1318
- return;
1319
- }
1320
- if (!resolved) continue;
1321
- let lane = resolved.lane;
1322
- if (lane !== void 0 && !this._declared_lanes.has(lane)) {
1323
- report_undeclared_lane(
1324
- this._reported,
1325
- reaction.handler.name,
1326
- resolved.target,
1327
- lane,
1328
- this._declared_lanes
1329
- );
1330
- lane = void 0;
1331
- }
1332
- const fixed = this._static_subscriptions.get(resolved.target);
1333
- const recorded = _nullishCoalesce(fixed, () => ( this._dynamic_subscriptions.get(resolved.target)));
1334
- const priority = _nullishCoalesce(resolved.priority, () => ( 0));
1335
- const upgraded = !recorded || !fixed && priority > recorded.priority;
1336
- const carried = upgraded ? { priority, lane } : { priority: recorded.priority, lane: recorded.lane };
1337
- const entry = correlated.get(resolved.target) || {
1338
- source: resolved.source,
1339
- priority: carried.priority,
1340
- lane: carried.lane,
1341
- upgraded,
1342
- missed: !recorded,
1343
- handler: reaction.handler.name,
1344
- correlated_at: void 0
1345
- };
1346
- const seen_in_scan = correlated.has(resolved.target);
1347
- const held_lane = _nullishCoalesce((seen_in_scan ? entry.lane : _optionalChain([recorded, 'optionalAccess', _61 => _61.lane])), () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
1348
- const held_priority = seen_in_scan ? entry.priority : _optionalChain([recorded, 'optionalAccess', _62 => _62.priority]);
1349
- const resolved_lane = _nullishCoalesce(lane, () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
1350
- if (held_priority === priority && held_lane !== resolved_lane)
1351
- report_lane_conflict(
1352
- this._reported,
1353
- reaction.handler.name,
1354
- resolved.target,
1355
- held_lane,
1356
- resolved_lane
1357
- );
1358
- if (carried.priority > entry.priority) {
1359
- entry.priority = carried.priority;
1360
- entry.lane = carried.lane;
1361
- entry.upgraded = upgraded;
1362
- entry.handler = reaction.handler.name;
1363
- }
1364
- if (this._in_fetch_window(resolved.source, event.stream))
1365
- entry.correlated_at = event.id;
1366
- correlated.set(resolved.target, entry);
1367
- }
1368
- }
1369
- last_id = event.id;
1370
- },
1371
- // Resolvers see `pii: null`: correlate runs actor-less, and one
1372
- // undecryptable row would otherwise stop every stream's reactions.
1373
- { after, limit, with_pii: false }
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
1374
1059
  );
1375
- if (this._declared_lanes.size > 1) await this._recall(correlated);
1376
- const read = last_id > after;
1377
- if (this._epoch !== epoch) return idle();
1378
- const streams = [];
1379
- for (const [stream, entry] of correlated) {
1380
- if (entry.upgraded || entry.correlated_at !== void 0)
1381
- streams.push({
1382
- stream,
1383
- source: entry.source,
1384
- priority: entry.priority,
1385
- lane: entry.lane,
1386
- correlated_at: entry.correlated_at
1387
- });
1388
- }
1389
- if (streams.length) {
1390
- const renewed_at = Date.now();
1391
- const { subscribed, correlating } = await this._cd.subscribe(
1392
- streams,
1393
- last_id,
1394
- lease ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
1395
- );
1396
- if (lease && correlating !== false)
1397
- this._lease_until = renewed_at + CORRELATION_LEASE_MS;
1398
- const marked = streams.filter(
1399
- (entry) => entry.correlated_at !== void 0
1400
- ).length;
1401
- this._checkpoint = last_id;
1402
- for (const { stream, priority, lane } of streams) {
1403
- if (_optionalChain([correlated, 'access', _63 => _63.get, 'call', _64 => _64(stream), 'optionalAccess', _65 => _65.upgraded]))
1404
- this._dynamic_subscriptions.set(stream, {
1405
- priority,
1406
- lane
1407
- });
1408
- }
1409
- return { kind: "scanned", last_id, subscribed, marked, read };
1060
+ this._timer = setTimeout(() => {
1061
+ this._timer = void 0;
1062
+ this._on_wake();
1063
+ }, delay);
1064
+ this._timer.unref();
1065
+ }
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;
1410
1071
  }
1411
- this._checkpoint = last_id;
1412
- if (!stopped && found !== limit) this._lowered = raised;
1413
- return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
1414
1072
  }
1415
- // Read the row of each target this scan had no record of (new or evicted),
1416
- // so a resolution that doesn't beat its priority keeps the row's lane.
1417
- // Only called with more than one lane declared.
1418
- async _recall(correlated) {
1419
- const missed = [...correlated].filter(([, entry]) => entry.missed);
1420
- await Promise.all(
1421
- missed.map(async ([stream, entry]) => {
1422
- let row;
1423
- await _chunkPRDX3HP6cjs.store.call(void 0, ).query_streams(
1424
- (position) => {
1425
- row = position;
1426
- },
1427
- { stream, stream_exact: true, limit: 1 }
1428
- );
1429
- if (!row) return;
1430
- this._dynamic_subscriptions.set(stream, {
1431
- priority: row.priority,
1432
- lane: row.lane
1433
- });
1434
- if (entry.priority > row.priority) return;
1435
- const held_lane = _nullishCoalesce(row.lane, () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
1436
- const resolved_lane = _nullishCoalesce(entry.lane, () => ( _chunkH6KVPVP4cjs.DEFAULT_LANE));
1437
- if (entry.priority === row.priority && held_lane !== resolved_lane)
1438
- report_lane_conflict(
1439
- this._reported,
1440
- entry.handler,
1441
- stream,
1442
- held_lane,
1443
- resolved_lane
1444
- );
1445
- entry.priority = row.priority;
1446
- entry.lane = row.lane;
1447
- entry.upgraded = false;
1448
- })
1449
- );
1450
- }
1451
- /** Release the lease early by re-acquiring it for zero ms. Best-effort. */
1452
- async release_correlation() {
1453
- try {
1454
- this._lease_until = 0;
1455
- this._epoch++;
1456
- await this._cd.subscribe([], void 0, {
1457
- key: this._key,
1458
- by: this._by,
1459
- millis: 0
1460
- });
1461
- } catch (error) {
1462
- _chunkPRDX3HP6cjs.log.call(void 0, ).warn(
1463
- `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)))}`
1464
- );
1465
- }
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;
1466
1085
  }
1467
- }, _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
+ }
1468
1099
 
1469
1100
  // src/internal/correlation-id.ts
1470
1101
 
@@ -1490,136 +1121,15 @@ function close_correlation(correlator, actor) {
1490
1121
  });
1491
1122
  }
1492
1123
 
1493
- // src/internal/drain-cycle.ts
1494
-
1495
-
1496
- // src/internal/backoff.ts
1497
- function compute_backoff_delay(retry, opts) {
1498
- if (!opts || opts.baseMs <= 0) return 0;
1499
- const r = Math.max(0, retry);
1500
- let delay;
1501
- switch (opts.strategy) {
1502
- case "fixed":
1503
- delay = opts.baseMs;
1504
- break;
1505
- case "linear":
1506
- delay = opts.baseMs * (r + 1);
1507
- break;
1508
- case "exponential":
1509
- delay = opts.baseMs * 2 ** r;
1510
- if (opts.maxMs !== void 0) delay = Math.min(delay, opts.maxMs);
1511
- break;
1512
- default: {
1513
- const _never = opts.strategy;
1514
- throw new Error(`unknown backoff strategy: ${String(_never)}`);
1515
- }
1516
- }
1517
- if (opts.jitter) delay = delay * (0.5 + Math.random());
1518
- return Math.max(0, Math.floor(delay));
1519
- }
1520
-
1521
- // src/internal/defer-timer.ts
1522
- var MAX_TIMER_DELAY_MS = 2147483647;
1523
- var DeferTimer = (_class4 = class {
1524
- __init14() {this._due = /* @__PURE__ */ new Map()}
1525
-
1526
-
1527
- /**
1528
- * @param on_wake - invoked once each time the earliest due-time elapses.
1529
- * The consumer re-schedules for whatever is still parked.
1530
- */
1531
- constructor(on_wake) {;_class4.prototype.__init14.call(this);
1532
- this._on_wake = on_wake;
1533
- }
1534
- /** Number of currently parked streams. */
1535
- get size() {
1536
- return this._due.size;
1537
- }
1538
- /**
1539
- * Park `stream` for a re-visit at `at` (ms since epoch). A plain
1540
- * overwrite: the caller computes the authoritative next-visit for the
1541
- * stream (the drain's `handle` already reconciles a stream's reactions
1542
- * into one result per cycle), so there is no stale value to merge against.
1543
- */
1544
- set(stream, at) {
1545
- this._due.set(stream, at);
1546
- }
1547
- /** Drop `stream` from the parked set (e.g. on a successful ack or block). */
1548
- delete(stream) {
1549
- this._due.delete(stream);
1550
- }
1551
- /**
1552
- * Drop every entry due at or before `before`. The drain calls it when a
1553
- * pass that started at `before` claimed nothing: whatever was due by then
1554
- * was handled elsewhere (another worker) or has no work left, so waking
1555
- * for it again would spin.
1556
- */
1557
- prune(before) {
1558
- for (const [stream, at] of this._due)
1559
- if (at <= before) this._due.delete(stream);
1560
- }
1561
- /**
1562
- * (Re)schedule the wake timer at the earliest pending due-time. Idempotent
1563
- * — collapses many parked streams into a single timer. A no-op clears any
1564
- * pending timer when the map is empty.
1565
- *
1566
- * The timer is `unref()`-ed so pending re-visits never keep the process
1567
- * alive on their own.
1568
- */
1569
- schedule() {
1570
- if (this._timer) clearTimeout(this._timer);
1571
- if (this._due.size === 0) {
1572
- this._timer = void 0;
1573
- return;
1574
- }
1575
- let earliest = Number.POSITIVE_INFINITY;
1576
- for (const t of this._due.values()) if (t < earliest) earliest = t;
1577
- const delay = Math.min(
1578
- Math.max(0, earliest - Date.now()),
1579
- MAX_TIMER_DELAY_MS
1580
- );
1581
- this._timer = setTimeout(() => {
1582
- this._timer = void 0;
1583
- this._on_wake();
1584
- }, delay);
1585
- this._timer.unref();
1586
- }
1587
- /** Cancel any pending wake timer. Idempotent. Leaves the parked set intact. */
1588
- stop() {
1589
- if (this._timer) {
1590
- clearTimeout(this._timer);
1591
- this._timer = void 0;
1592
- }
1593
- }
1594
- }, _class4);
1595
-
1596
- // src/internal/drain-ratio.ts
1597
- var RATIO_MIN = 0.2;
1598
- var RATIO_MAX = 0.8;
1599
- var RATIO_DEFAULT = 0.5;
1600
- function compute_lag_lead_ratio(handled, lagging, leading) {
1601
- let lagging_handled = 0;
1602
- let leading_handled = 0;
1603
- for (const { lease, handled: count } of handled) {
1604
- if (lease.lagging) lagging_handled += count;
1605
- else leading_handled += count;
1606
- }
1607
- const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;
1608
- const leading_avg = leading > 0 ? leading_handled / leading : 0;
1609
- const total = lagging_avg + leading_avg;
1610
- if (total === 0) return RATIO_DEFAULT;
1611
- return Math.max(RATIO_MIN, Math.min(RATIO_MAX, lagging_avg / total));
1612
- }
1613
-
1614
1124
  // src/internal/drain-ops.ts
1615
- var claim = (lagging, leading, by, millis, lane) => _chunkPRDX3HP6cjs.store.call(void 0, ).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);
1616
1126
  async function fetch(leased, eventLimit) {
1617
1127
  return Promise.all(
1618
1128
  leased.map(async ({ stream, source, at, lagging }) => {
1619
1129
  const events = [];
1620
- const stream_exact = source !== void 0 && _chunkPRDX3HP6cjs.is_literal_source.call(void 0, source) ? true : void 0;
1130
+ const stream_exact = source !== void 0 && _chunk4UWU5FANcjs.is_literal_source.call(void 0, source, stream) ? true : void 0;
1621
1131
  try {
1622
- await _chunkPRDX3HP6cjs.store.call(void 0, ).query((e) => events.push(e), {
1132
+ await _chunk4UWU5FANcjs.store.call(void 0, ).query((e) => events.push(e), {
1623
1133
  stream: source,
1624
1134
  stream_exact,
1625
1135
  after: at,
@@ -1632,23 +1142,23 @@ async function fetch(leased, eventLimit) {
1632
1142
  at,
1633
1143
  lagging,
1634
1144
  events: [],
1635
- error: _nullishCoalesce(_optionalChain([error, 'optionalAccess', _66 => _66.message]), () => ( String(error)))
1145
+ error: _nullishCoalesce(_optionalChain([error, 'optionalAccess', _51 => _51.message]), () => ( String(error)))
1636
1146
  };
1637
1147
  }
1638
1148
  return { stream, source, at, lagging, events };
1639
1149
  })
1640
1150
  );
1641
1151
  }
1642
- var ack = (leases) => _chunkPRDX3HP6cjs.store.call(void 0, ).ack(leases);
1643
- var block = (leases) => _chunkPRDX3HP6cjs.store.call(void 0, ).block(leases);
1644
- var subscribe = (streams, correlated_at, correlator) => _chunkPRDX3HP6cjs.store.call(void 0, ).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);
1645
1155
 
1646
1156
  // src/internal/event-sourcing.ts
1647
1157
  var _actpatch = require('@rotorsoft/act-patch');
1648
- var _zod = require('zod');
1158
+
1649
1159
  var bare_patch = (_me, state2, partial) => _actpatch.patch.call(void 0, state2, partial);
1650
1160
  var value_at = (value, path) => path.reduce(
1651
- (at, key) => _optionalChain([at, 'optionalAccess', _67 => _67[key]]),
1161
+ (at, key) => _optionalChain([at, 'optionalAccess', _52 => _52[key]]),
1652
1162
  value
1653
1163
  );
1654
1164
  var check_invariants = (target, state2, schema, pii_aware) => {
@@ -1656,29 +1166,29 @@ var check_invariants = (target, state2, schema, pii_aware) => {
1656
1166
  try {
1657
1167
  result = schema.safeParse(state2);
1658
1168
  } catch (error) {
1659
- throw new (0, _chunkH6KVPVP4cjs.ValidationError)(target, state2, error);
1169
+ throw new (0, _chunkBCA423WPcjs.ValidationError)(target, state2, error);
1660
1170
  }
1661
1171
  if (result.success) return;
1662
1172
  const issues = pii_aware ? result.error.issues.filter((issue) => {
1663
1173
  const value = value_at(state2, issue.path);
1664
- return value !== _chunkH6KVPVP4cjs.REDACTED && value !== _chunkH6KVPVP4cjs.SHREDDED;
1174
+ return value !== _chunkBCA423WPcjs.REDACTED && value !== _chunkBCA423WPcjs.SHREDDED;
1665
1175
  }) : result.error.issues;
1666
1176
  if (issues.length)
1667
- throw new (0, _chunkH6KVPVP4cjs.ValidationError)(
1177
+ throw new (0, _chunkBCA423WPcjs.ValidationError)(
1668
1178
  target,
1669
1179
  state2,
1670
1180
  _zod.prettifyError.call(void 0, new (0, _zod.ZodError)(issues))
1671
1181
  );
1672
1182
  };
1673
1183
  var DEFAULT_BATCH = 500;
1674
- var cache_put = (stream, entry) => _chunkPRDX3HP6cjs.cache.call(void 0, ).set(stream, entry).catch(
1675
- (err) => _chunkPRDX3HP6cjs.log.call(void 0, ).warn(
1184
+ var cache_put = (stream, entry) => _chunk4UWU5FANcjs.cache.call(void 0, ).set(stream, entry).catch(
1185
+ (err) => _chunk4UWU5FANcjs.log.call(void 0, ).warn(
1676
1186
  err,
1677
1187
  "cache set skipped; the next load re-folds from the store"
1678
1188
  )
1679
1189
  );
1680
- var cache_drop = (stream) => _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(stream).catch(
1681
- (err) => _chunkPRDX3HP6cjs.log.call(void 0, ).warn(
1190
+ var cache_drop = (stream) => _chunk4UWU5FANcjs.cache.call(void 0, ).invalidate(stream).catch(
1191
+ (err) => _chunk4UWU5FANcjs.log.call(void 0, ).warn(
1682
1192
  err,
1683
1193
  "cache invalidate skipped; a stale checkpoint re-folds from its event_id"
1684
1194
  )
@@ -1686,9 +1196,9 @@ var cache_drop = (stream) => _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(s
1686
1196
  async function snap(snapshot) {
1687
1197
  const { id, stream, name, meta, version } = snapshot.event;
1688
1198
  try {
1689
- const [committed] = await _chunkPRDX3HP6cjs.store.call(void 0, ).commit(
1199
+ const [committed] = await _chunk4UWU5FANcjs.store.call(void 0, ).commit(
1690
1200
  stream,
1691
- [{ name: _chunkH6KVPVP4cjs.SNAP_EVENT, data: snapshot.state }],
1201
+ [{ name: _chunkBCA423WPcjs.SNAP_EVENT, data: snapshot.state }],
1692
1202
  {
1693
1203
  correlation: meta.correlation,
1694
1204
  causation: { event: { id, name, stream } }
@@ -1699,22 +1209,22 @@ async function snap(snapshot) {
1699
1209
  return committed;
1700
1210
  } catch (error) {
1701
1211
  const reason = error instanceof Error ? error.message : String(error);
1702
- _chunkPRDX3HP6cjs.log.call(void 0, ).warn(
1212
+ _chunk4UWU5FANcjs.log.call(void 0, ).warn(
1703
1213
  `Snapshot write failed on stream "${stream}": ${reason} \u2014 cold starts will replay full history until snapshots succeed.`
1704
1214
  );
1705
1215
  }
1706
1216
  }
1707
1217
  async function tombstone(stream, expectedVersion, correlation) {
1708
1218
  try {
1709
- const [committed] = await _chunkPRDX3HP6cjs.store.call(void 0, ).commit(
1219
+ const [committed] = await _chunk4UWU5FANcjs.store.call(void 0, ).commit(
1710
1220
  stream,
1711
- [{ name: _chunkH6KVPVP4cjs.TOMBSTONE_EVENT, data: {} }],
1221
+ [{ name: _chunkBCA423WPcjs.TOMBSTONE_EVENT, data: {} }],
1712
1222
  { correlation, causation: {} },
1713
1223
  expectedVersion
1714
1224
  );
1715
1225
  return committed;
1716
1226
  } catch (error) {
1717
- if (error instanceof _chunkH6KVPVP4cjs.ConcurrencyError) return void 0;
1227
+ if (error instanceof _chunkBCA423WPcjs.ConcurrencyError) return void 0;
1718
1228
  throw error;
1719
1229
  }
1720
1230
  }
@@ -1744,9 +1254,9 @@ async function scan(source, opts = {}, callback) {
1744
1254
  if (drop_closed_streams) {
1745
1255
  await source.query(
1746
1256
  (e) => {
1747
- if (e.name === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT) closed_streams.add(e.stream);
1257
+ if (e.name === _chunkBCA423WPcjs.TOMBSTONE_EVENT) closed_streams.add(e.stream);
1748
1258
  },
1749
- { names: [_chunkH6KVPVP4cjs.TOMBSTONE_EVENT] }
1259
+ { names: [_chunkBCA423WPcjs.TOMBSTONE_EVENT] }
1750
1260
  );
1751
1261
  }
1752
1262
  let max_id;
@@ -1768,16 +1278,16 @@ async function scan(source, opts = {}, callback) {
1768
1278
  if (!is_valid(event))
1769
1279
  throw new Error(`Invalid event at index ${processed}`);
1770
1280
  if (on_progress) on_progress({ processed, id: event.id, max_id });
1771
- if (drop_snapshots && event.name === _chunkH6KVPVP4cjs.SNAP_EVENT) {
1281
+ if (drop_snapshots && event.name === _chunkBCA423WPcjs.SNAP_EVENT) {
1772
1282
  dropped_snaps++;
1773
1283
  return;
1774
1284
  }
1775
- if (closed_streams.has(event.stream) && event.name !== _chunkH6KVPVP4cjs.TOMBSTONE_EVENT) {
1285
+ if (closed_streams.has(event.stream) && event.name !== _chunkBCA423WPcjs.TOMBSTONE_EVENT) {
1776
1286
  dropped_closed++;
1777
1287
  return;
1778
1288
  }
1779
1289
  let migrated = event;
1780
- const migration = _optionalChain([event_migrations, 'optionalAccess', _68 => _68[event.name]]);
1290
+ const migration = _optionalChain([event_migrations, 'optionalAccess', _53 => _53[event.name]]);
1781
1291
  if (migration) {
1782
1292
  const old_data = migration.from_schema.parse(event.data);
1783
1293
  const new_data = migration.migrate(old_data);
@@ -1799,7 +1309,7 @@ async function scan(source, opts = {}, callback) {
1799
1309
  return;
1800
1310
  }
1801
1311
  let remapped = migrated;
1802
- const caused_by = _optionalChain([migrated, 'access', _69 => _69.meta, 'access', _70 => _70.causation, 'access', _71 => _71.event, 'optionalAccess', _72 => _72.id]);
1312
+ const caused_by = _optionalChain([migrated, 'access', _54 => _54.meta, 'access', _55 => _55.causation, 'access', _56 => _56.event, 'optionalAccess', _57 => _57.id]);
1803
1313
  if (caused_by !== void 0) {
1804
1314
  const new_caused_by = id_map.get(caused_by);
1805
1315
  if (new_caused_by !== void 0 && new_caused_by !== caused_by) {
@@ -1840,18 +1350,18 @@ async function load(me, target, callback, patch_fn = bare_patch) {
1840
1350
  const { stream, actor, asOf } = target;
1841
1351
  const time_travel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
1842
1352
  const seeded = time_travel && asOf.limit === void 0 && !asOf.created_after;
1843
- const cached = time_travel ? void 0 : await _chunkPRDX3HP6cjs.cache.call(void 0, ).get(stream);
1353
+ const cached = time_travel ? void 0 : await _chunk4UWU5FANcjs.cache.call(void 0, ).get(stream);
1844
1354
  const cache_hit = !!cached;
1845
- let state2 = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _73 => _73.state]), () => ( (me.init ? me.init() : {})));
1846
- let patches = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _74 => _74.patches]), () => ( 0));
1847
- let snaps = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _75 => _75.snaps]), () => ( 0));
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));
1848
1358
  let replayed = 0;
1849
1359
  let event;
1850
- await _chunkPRDX3HP6cjs.store.call(void 0, ).query(
1360
+ await _chunk4UWU5FANcjs.store.call(void 0, ).query(
1851
1361
  (raw) => {
1852
- if (seeded && raw.name === _chunkH6KVPVP4cjs.SNAP_EVENT && replayed > 0) return;
1362
+ if (seeded && raw.name === _chunkBCA423WPcjs.SNAP_EVENT && replayed > 0) return;
1853
1363
  event = me.view(raw, actor);
1854
- if (event.name === _chunkH6KVPVP4cjs.SNAP_EVENT) {
1364
+ if (event.name === _chunkBCA423WPcjs.SNAP_EVENT) {
1855
1365
  state2 = event.data;
1856
1366
  snaps++;
1857
1367
  patches = 0;
@@ -1860,12 +1370,12 @@ async function load(me, target, callback, patch_fn = bare_patch) {
1860
1370
  state2 = patch_fn(me, state2, me.patch[event.name](event, state2), event);
1861
1371
  patches++;
1862
1372
  replayed++;
1863
- } else if (event.name !== _chunkH6KVPVP4cjs.TOMBSTONE_EVENT) {
1864
- _chunkPRDX3HP6cjs.log.call(void 0, ).warn(
1373
+ } else if (event.name !== _chunkBCA423WPcjs.TOMBSTONE_EVENT) {
1374
+ _chunk4UWU5FANcjs.log.call(void 0, ).warn(
1865
1375
  `Skipping unknown event "${String(event.name)}" on stream "${stream}" (id=${event.id}) \u2014 no reducer in state "${me.name}"`
1866
1376
  );
1867
1377
  }
1868
- _optionalChain([callback, 'optionalCall', _76 => _76({
1378
+ _optionalChain([callback, 'optionalCall', _61 => _61({
1869
1379
  event,
1870
1380
  state: state2,
1871
1381
  version: event.version,
@@ -1889,7 +1399,7 @@ async function load(me, target, callback, patch_fn = bare_patch) {
1889
1399
  ) : time_travel ? asOf : { with_snaps: true }
1890
1400
  }
1891
1401
  );
1892
- const head_is_tombstone = _optionalChain([event, 'optionalAccess', _77 => _77.name]) === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT;
1402
+ const head_is_tombstone = _optionalChain([event, 'optionalAccess', _62 => _62.name]) === _chunkBCA423WPcjs.TOMBSTONE_EVENT;
1893
1403
  if (replayed > 0 && !time_travel && event && !me.pii_aware && !head_is_tombstone) {
1894
1404
  await cache_put(stream, {
1895
1405
  stream,
@@ -1903,9 +1413,9 @@ async function load(me, target, callback, patch_fn = bare_patch) {
1903
1413
  return {
1904
1414
  event,
1905
1415
  state: state2,
1906
- version: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _78 => _78.version]), () => ( _optionalChain([cached, 'optionalAccess', _79 => _79.version]))), () => ( -1)),
1416
+ version: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _63 => _63.version]), () => ( _optionalChain([cached, 'optionalAccess', _64 => _64.version]))), () => ( -1)),
1907
1417
  // Captured with `state`, so consumers never race a separate cache lookup.
1908
- id: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _80 => _80.id]), () => ( _optionalChain([cached, 'optionalAccess', _81 => _81.event_id]))), () => ( -1)),
1418
+ id: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _65 => _65.id]), () => ( _optionalChain([cached, 'optionalAccess', _66 => _66.event_id]))), () => ( -1)),
1909
1419
  patches,
1910
1420
  snaps,
1911
1421
  cache_hit,
@@ -1915,11 +1425,11 @@ async function load(me, target, callback, patch_fn = bare_patch) {
1915
1425
  async function action(me, action2, target, payload, options, patch_fn = bare_patch) {
1916
1426
  const { stream, expectedVersion, actor } = target;
1917
1427
  if (!stream) throw new Error("Missing target stream");
1918
- const reactingTo = _optionalChain([options, 'optionalAccess', _82 => _82.reactingTo]);
1919
- const correlator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _83 => _83.correlator]), () => ( default_correlator));
1920
- const validated = _chunkPRDX3HP6cjs.validate.call(void 0, action2, payload, me.actions[action2]);
1921
- const opts = _optionalChain([me, 'access', _84 => _84.options, 'optionalAccess', _85 => _85[action2]]);
1922
- const max_retries = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _86 => _86.maxRetries]), () => ( 0));
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));
1923
1433
  for (let attempt = 0; ; attempt++) {
1924
1434
  try {
1925
1435
  const snapshot = await load(
@@ -1928,21 +1438,21 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
1928
1438
  void 0,
1929
1439
  patch_fn
1930
1440
  );
1931
- if (_optionalChain([snapshot, 'access', _87 => _87.event, 'optionalAccess', _88 => _88.name]) === _chunkH6KVPVP4cjs.TOMBSTONE_EVENT)
1932
- throw new (0, _chunkH6KVPVP4cjs.StreamClosedError)(stream);
1441
+ if (_optionalChain([snapshot, 'access', _72 => _72.event, 'optionalAccess', _73 => _73.name]) === _chunkBCA423WPcjs.TOMBSTONE_EVENT)
1442
+ throw new (0, _chunkBCA423WPcjs.StreamClosedError)(stream);
1933
1443
  const expected = _nullishCoalesce(expectedVersion, () => ( snapshot.version));
1934
- for (const { valid, description } of _nullishCoalesce(_optionalChain([me, 'access', _89 => _89.given, 'optionalAccess', _90 => _90[action2]]), () => ( [])))
1444
+ for (const { valid, description } of _nullishCoalesce(_optionalChain([me, 'access', _74 => _74.given, 'optionalAccess', _75 => _75[action2]]), () => ( [])))
1935
1445
  if (!valid(snapshot.state, actor))
1936
- throw new (0, _chunkH6KVPVP4cjs.InvariantError)(
1446
+ throw new (0, _chunkBCA423WPcjs.InvariantError)(
1937
1447
  action2,
1938
1448
  validated,
1939
1449
  target,
1940
1450
  snapshot,
1941
1451
  description
1942
1452
  );
1943
- for (const { holds, description } of _nullishCoalesce(_optionalChain([me, 'access', _91 => _91.requires, 'optionalAccess', _92 => _92[action2]]), () => ( [])))
1453
+ for (const { holds, description } of _nullishCoalesce(_optionalChain([me, 'access', _76 => _76.requires, 'optionalAccess', _77 => _77[action2]]), () => ( [])))
1944
1454
  if (!holds(validated, snapshot.state, actor))
1945
- throw new (0, _chunkH6KVPVP4cjs.PreconditionError)(
1455
+ throw new (0, _chunkBCA423WPcjs.PreconditionError)(
1946
1456
  action2,
1947
1457
  validated,
1948
1458
  target,
@@ -1955,11 +1465,11 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
1955
1465
  const tuples = Array.isArray(result[0]) ? result : [result];
1956
1466
  const events = tuples.map(([name, data]) => ({
1957
1467
  name,
1958
- data: _chunkPRDX3HP6cjs.validate.call(void 0, name, data, me.events[name])
1468
+ data: _chunk4UWU5FANcjs.validate.call(void 0, name, data, me.events[name])
1959
1469
  }));
1960
1470
  const emitted = events.map((e) => me.message(e));
1961
1471
  const meta = {
1962
- correlation: _optionalChain([reactingTo, 'optionalAccess', _93 => _93.meta, 'access', _94 => _94.correlation]) || correlator({
1472
+ correlation: _optionalChain([reactingTo, 'optionalAccess', _78 => _78.meta, 'access', _79 => _79.correlation]) || correlator({
1963
1473
  action: action2,
1964
1474
  state: me.name,
1965
1475
  stream,
@@ -2002,9 +1512,9 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
2002
1512
  );
2003
1513
  let committed;
2004
1514
  try {
2005
- committed = await _chunkPRDX3HP6cjs.store.call(void 0, ).commit(stream, emitted, meta, expected);
1515
+ committed = await _chunk4UWU5FANcjs.store.call(void 0, ).commit(stream, emitted, meta, expected);
2006
1516
  } catch (error) {
2007
- if (error instanceof _chunkH6KVPVP4cjs.ConcurrencyError) void cache_drop(stream);
1517
+ if (error instanceof _chunkBCA423WPcjs.ConcurrencyError) void cache_drop(stream);
2008
1518
  throw error;
2009
1519
  }
2010
1520
  const snapshots = committed.map((row, i) => ({
@@ -2019,31 +1529,31 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
2019
1529
  replayed: snapshot.replayed
2020
1530
  }));
2021
1531
  const last = snapshots.at(-1);
2022
- const snap_event = _optionalChain([me, 'access', _95 => _95.snap, 'optionalCall', _96 => _96(last)]) ? await snap(last) : void 0;
1532
+ const snap_event = _optionalChain([me, 'access', _80 => _80.snap, 'optionalCall', _81 => _81(last)]) ? await snap(last) : void 0;
2023
1533
  if (!me.pii_aware)
2024
1534
  void cache_put(stream, {
2025
1535
  stream,
2026
1536
  state: last.state,
2027
- version: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _97 => _97.version]), () => ( last.event.version)),
2028
- event_id: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _98 => _98.id]), () => ( last.event.id)),
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)),
2029
1539
  patches: snap_event ? 0 : last.patches,
2030
1540
  snaps: snap_event ? last.snaps + 1 : last.snaps
2031
1541
  });
2032
1542
  return snapshots;
2033
1543
  } catch (error) {
2034
- if (!(error instanceof _chunkH6KVPVP4cjs.ConcurrencyError)) throw error;
1544
+ if (!(error instanceof _chunkBCA423WPcjs.ConcurrencyError)) throw error;
2035
1545
  if (expectedVersion !== void 0) throw error;
2036
1546
  if (attempt >= max_retries) throw error;
2037
- if (_optionalChain([opts, 'optionalAccess', _99 => _99.backoff])) {
1547
+ if (_optionalChain([opts, 'optionalAccess', _84 => _84.backoff])) {
2038
1548
  const delay_ms = compute_backoff_delay(attempt, opts.backoff);
2039
- if (delay_ms > 0) await _chunkPRDX3HP6cjs.sleep.call(void 0, delay_ms);
1549
+ if (delay_ms > 0) await _chunk4UWU5FANcjs.sleep.call(void 0, delay_ms);
2040
1550
  }
2041
1551
  }
2042
1552
  }
2043
1553
  }
2044
1554
 
2045
1555
  // src/internal/tracing.ts
2046
- var PRETTY = _chunkPRDX3HP6cjs.config.call(void 0, ).env !== "production";
1556
+ var PRETTY = _chunk4UWU5FANcjs.config.call(void 0, ).env !== "production";
2047
1557
  var C_BLUE = "\x1B[38;5;39m";
2048
1558
  var C_ORANGE = "\x1B[38;5;208m";
2049
1559
  var C_GREEN = "\x1B[38;5;42m";
@@ -2089,9 +1599,9 @@ var as_of_marker = (asOf) => {
2089
1599
  return parts.length ? ` (as-of ${parts.join(" ")})` : " (as-of)";
2090
1600
  };
2091
1601
  var traced = (inner, exit, entry) => (async (...args) => {
2092
- _optionalChain([entry, 'optionalCall', _100 => _100(...args)]);
1602
+ _optionalChain([entry, 'optionalCall', _85 => _85(...args)]);
2093
1603
  const result = await inner(...args);
2094
- _optionalChain([exit, 'optionalCall', _101 => _101(result, ...args)]);
1604
+ _optionalChain([exit, 'optionalCall', _86 => _86(result, ...args)]);
2095
1605
  return result;
2096
1606
  });
2097
1607
  function build_es(logger, correlator = default_correlator, patch_fn = bare_patch) {
@@ -2100,7 +1610,7 @@ function build_es(logger, correlator = default_correlator, patch_fn = bare_patch
2100
1610
  action_name,
2101
1611
  target,
2102
1612
  payload,
2103
- { ...options, correlator: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _102 => _102.correlator]), () => ( correlator)) },
1613
+ { ...options, correlator: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.correlator]), () => ( correlator)) },
2104
1614
  patch_fn
2105
1615
  );
2106
1616
  const bound_load = (me, target, callback) => load(me, target, callback, patch_fn);
@@ -2174,7 +1684,7 @@ function build_drain(logger) {
2174
1684
  subscribe: logger.level !== "trace" ? subscribe : traced(subscribe, (result, streams) => {
2175
1685
  if (!result.subscribed) return;
2176
1686
  const lanes = new Set(streams.map((s) => _nullishCoalesce(s.lane, () => ( "default"))));
2177
- const uniform_lane = lanes.size === 1 ? _optionalChain([streams, 'access', _103 => _103[0], 'optionalAccess', _104 => _104.lane]) : void 0;
1687
+ const uniform_lane = lanes.size === 1 ? _optionalChain([streams, 'access', _88 => _88[0], 'optionalAccess', _89 => _89.lane]) : void 0;
2178
1688
  const data = streams.map(
2179
1689
  ({ stream, lane }) => uniform_lane || !lane || lane === "default" ? hue(C_STREAM, stream) : `${hue(C_STREAM, stream)}${dim(`[${lane}]`)}`
2180
1690
  ).join(" ");
@@ -2186,7 +1696,7 @@ function build_drain(logger) {
2186
1696
  }
2187
1697
  function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
2188
1698
  if (logger.level !== "trace" || !leased.length) return;
2189
- const lane = _optionalChain([leased, 'access', _105 => _105[0], 'optionalAccess', _106 => _106.lane]);
1699
+ const lane = _optionalChain([leased, 'access', _90 => _90[0], 'optionalAccess', _91 => _91.lane]);
2190
1700
  const fetch_by_stream = new Map(fetched.map((f) => [f.stream, f]));
2191
1701
  const acked_by_stream = new Map(acked.map((a) => [a.stream, a.at]));
2192
1702
  const blocked_by_stream = new Map(blocked.map((b) => [b.stream, b.error]));
@@ -2195,8 +1705,8 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
2195
1705
  );
2196
1706
  const detail = leased.map(({ stream, at, retry }) => {
2197
1707
  const f = fetch_by_stream.get(stream);
2198
- const key = _optionalChain([f, 'optionalAccess', _107 => _107.source]) ? `${hue(C_STREAM, stream)}${dim(`<-${f.source}`)}` : hue(C_STREAM, stream);
2199
- const events = _optionalChain([f, 'optionalAccess', _108 => _108.events, 'access', _109 => _109.length]) ? ` ${dim(
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(
2200
1710
  `[${f.events.map(({ id, name }) => `#${id} ${String(name)}`).join(", ")}]`
2201
1711
  )}` : "";
2202
1712
  const acked_at = acked_by_stream.get(stream);
@@ -2209,326 +1719,1216 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
2209
1719
  if (blocked_error !== void 0) {
2210
1720
  fail_part = `${hue(C_ERR, `\u2717 @${failed_at}/${retry}`)} ${dim(`(${blocked_error})`)}`;
2211
1721
  } else {
2212
- 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);
2213
2530
  }
2214
- }
2215
- let tail;
2216
- if (ack_part && fail_part) tail = ` ${ack_part} ${fail_part}`;
2217
- else if (ack_part) tail = ` ${ack_part}`;
2218
- else if (fail_part) tail = ` ${fail_part}`;
2219
- else tail = ` ${dim(`\u2298 @${at}/${retry}`)}`;
2220
- return `${key}${events}${tail}`;
2221
- }).join(", ");
2222
- logger.trace(`${drain_caption("drained", lane)} ${detail}`);
2223
- }
2224
-
2225
- // src/internal/drain-cycle.ts
2226
- function budget_exhausted(lease, options, store_failing) {
2227
- if (store_failing || !_optionalChain([options, 'optionalAccess', _110 => _110.blockOnError]) || lease.retry <= options.maxRetries)
2228
- return void 0;
2229
- 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.`;
2230
- _chunkPRDX3HP6cjs.log.call(void 0, ).error(error);
2231
- return { lease, handled: 0, acked_at: lease.at, error, block: true };
2531
+ })
2532
+ );
2533
+ return { guarded, guard_events };
2232
2534
  }
2233
- function fetch_failure_policy(registry) {
2234
- let blockOnError = true;
2235
- let maxRetries = 0;
2236
- for (const register of Object.values(registry.events))
2237
- for (const reaction of register.reactions.values()) {
2238
- blockOnError &&= reaction.options.blockOnError;
2239
- maxRetries = Math.max(maxRetries, reaction.options.maxRetries);
2240
- }
2241
- return { blockOnError, maxRetries };
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;
2242
2552
  }
2243
- function finalize(lease, handled, at, error, options, logger, failed_at) {
2244
- if (!error) return { lease, handled, acked_at: at };
2245
- logger.error(error);
2246
- const non_retryable = error instanceof _chunkH6KVPVP4cjs.NonRetryableError;
2247
- const block2 = options.blockOnError && (non_retryable || lease.retry >= options.maxRetries);
2248
- if (block2)
2249
- logger.error(
2250
- non_retryable ? `Blocking ${lease.stream} on non-retryable error.` : `Blocking ${lease.stream} after ${lease.retry} retries.`
2251
- );
2252
- const next_attempt_at = block2 ? void 0 : Date.now() + compute_backoff_delay(lease.retry, _nullishCoalesce(options.backoff, () => ( _chunkPRDX3HP6cjs.DEFAULT_BACKOFF)));
2253
- return {
2254
- lease,
2255
- handled,
2256
- acked_at: at,
2257
- error: error.message,
2258
- block: block2,
2259
- next_attempt_at,
2260
- failed_at
2261
- };
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
+ }
2262
2558
  }
2263
- function warn_misrouted(seen, stream, handler, event) {
2264
- report_once(
2265
- seen,
2266
- `${stream}|${handler}|${event}`,
2267
- `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.`
2268
- );
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
+ });
2269
2567
  }
2270
- async function run_drain_cycle(deps, cycle) {
2271
- const { ops, registry, batch_handlers, handle, handle_batch, lane } = deps;
2272
- const {
2273
- lagging,
2274
- leading,
2275
- eventLimit,
2276
- leaseMillis,
2277
- misrouted,
2278
- store_failing
2279
- } = cycle;
2280
- const leased = await ops.claim(
2281
- lagging,
2282
- leading,
2283
- _crypto.randomUUID.call(void 0, ),
2284
- leaseMillis,
2285
- lane
2286
- );
2287
- if (!leased.length) return void 0;
2288
- const fetched = await ops.fetch(leased, eventLimit);
2289
- const fetch_map = /* @__PURE__ */ new Map();
2290
- const fetch_window_at = fetched.reduce(
2291
- (max, { at, events }) => Math.max(max, _optionalChain([events, 'access', _111 => _111.at, 'call', _112 => _112(-1), 'optionalAccess', _113 => _113.id]) || at),
2292
- 0
2293
- );
2294
- for (const f of fetched) {
2295
- const { stream, events } = f;
2296
- let failed;
2297
- const payloads = events.flatMap((event) => {
2298
- const register = registry.events[event.name];
2299
- if (!register) return [];
2300
- return [...register.reactions.values()].filter((reaction) => {
2301
- const resolver = reaction.resolver;
2302
- const dynamic = typeof resolver === "function";
2303
- let resolved;
2304
- try {
2305
- resolved = dynamic ? resolver(event) : resolver;
2306
- } catch (error) {
2307
- failed ??= {
2308
- error: new Error(
2309
- `Resolver of reaction "${reaction.handler.name}" threw on ${String(event.name)} #${event.id} (stream "${event.stream}"): ${String(error)}`
2310
- ),
2311
- options: reaction.options
2312
- };
2313
- 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 }
2314
2579
  }
2315
- if (!resolved || resolved.target !== stream) return false;
2316
- if (!dynamic || !batch_handlers.has(stream)) return true;
2317
- warn_misrouted(
2318
- misrouted,
2319
- stream,
2320
- reaction.handler.name,
2321
- String(event.name)
2322
- );
2323
- return false;
2324
- }).map((reaction) => ({ ...reaction, event }));
2325
- });
2326
- fetch_map.set(stream, { fetch: f, payloads, failed });
2327
- }
2328
- const handled = await Promise.all(
2329
- leased.map((lease) => {
2330
- const entry = fetch_map.get(lease.stream);
2331
- if (entry.fetch.error !== void 0) {
2332
- const policy = fetch_failure_policy(registry);
2333
- return Promise.resolve(
2334
- finalize(
2335
- lease,
2336
- 0,
2337
- lease.at,
2338
- new Error(`Fetch failed for ${lease.stream}: ${entry.fetch.error}`),
2339
- store_failing ? { ...policy, blockOnError: false } : policy,
2340
- deps.logger
2341
- )
2342
- );
2343
2580
  }
2344
- if (entry.failed)
2345
- return Promise.resolve(
2346
- finalize(
2347
- lease,
2348
- 0,
2349
- lease.at,
2350
- entry.failed.error,
2351
- entry.failed.options,
2352
- deps.logger
2353
- )
2354
- );
2355
- const at = _optionalChain([entry, 'access', _114 => _114.fetch, 'access', _115 => _115.events, 'access', _116 => _116.at, 'call', _117 => _117(-1), 'optionalAccess', _118 => _118.id]) || fetch_window_at;
2356
- const { payloads } = entry;
2357
- const exhausted = budget_exhausted(
2358
- lease,
2359
- _optionalChain([payloads, 'access', _119 => _119[0], 'optionalAccess', _120 => _120.options]),
2360
- store_failing
2361
- );
2362
- if (exhausted) return Promise.resolve(exhausted);
2363
- const batchHandler = batch_handlers.get(lease.stream);
2364
- if (batchHandler && payloads.length > 0) {
2365
- 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);
2366
2599
  }
2367
- return handle({ ...lease, at }, payloads);
2368
2600
  })
2369
2601
  );
2370
- const to_block = handled.filter(({ block: block2 }) => block2).map(({ lease, error }) => ({ ...lease, error }));
2371
- const blocked = to_block.length ? await ops.block(to_block) : [];
2372
- if (blocked.length) deps.on_blocked(blocked);
2373
- const submitted = handled.flatMap((h, i) => {
2374
- const advance = h.handled > 0 ? h.acked_at : leased[i].at;
2375
- 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 } : [];
2376
- });
2377
- const acked = submitted.length ? await ops.ack(submitted) : [];
2378
- const expected = submitted.filter((l) => l.due === void 0).length;
2379
- if (acked.length < expected)
2380
- _chunkPRDX3HP6cjs.log.call(void 0, ).warn(
2381
- `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.`
2382
- );
2383
- const closeable = handled.filter((h) => h.close !== void 0).map((h) => h.close);
2384
- return { leased, fetched, handled, acked, blocked, closeable };
2602
+ return truncated;
2385
2603
  }
2386
- var EMPTY_DRAIN = {
2387
- fetched: [],
2388
- leased: [],
2389
- acked: [],
2390
- blocked: []
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);
2391
2612
  };
2392
- function merge_drains(drains) {
2393
- return {
2394
- fetched: drains.flatMap((d) => d.fetched),
2395
- leased: drains.flatMap((d) => d.leased),
2396
- acked: drains.flatMap((d) => d.acked),
2397
- blocked: drains.flatMap((d) => d.blocked)
2398
- };
2399
- }
2400
- var RETRY = "";
2401
- var DrainController = (_class5 = class {
2402
- // Armed while `_raised` is ahead of `_lowered` (the raise count the last
2403
- // empty claim saw), so a claim never lowers over a raise that landed
2404
- // during it.
2405
- __init15() {this._raised = 0}
2406
- __init16() {this._lowered = 0}
2407
- __init17() {this._ratio = 0.5}
2408
- // Local wake at the earliest parked (backoff or defer) visit, or at the
2409
- // lease expiry after a failed pass (the {@link RETRY} key); the schedule
2410
- // itself is persisted. On an idle app nothing else would drain it. It
2411
- // drains until a pass leases nothing or the controller stops, and an entry
2412
- // stays until handled or until a later pass claims nothing.
2413
- __init18() {this._defer = new DeferTimer(() => {
2414
- this.arm();
2415
- void this._deps.run_scoped(async () => {
2416
- while ((await this.drain()).leased.length > 0) ;
2417
- });
2418
- })}
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
+ );
2620
+ }
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, )}
2419
2632
 
2420
- __init19() {this._misrouted = /* @__PURE__ */ new Set()}
2421
- __init20() {this._stopped = false}
2422
- // The pass in flight. Never rejects; graceful shutdown waits on it.
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}
2423
2645
 
2646
+ // Bounded by `maxSubscribedStreams`; static records live apart so eviction
2647
+ // never lets a resolution re-lane them.
2424
2648
 
2425
- constructor(deps) {;_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);
2426
- this._deps = deps;
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;
2674
+ }
2675
+ get checkpoint() {
2676
+ return this._checkpoint;
2427
2677
  }
2678
+ /** A commit (local or remote) may have produced uncorrelated events. */
2428
2679
  arm() {
2429
2680
  this._raised++;
2430
2681
  }
2431
- /** Cold start: re-seed a persisted `deferred_at` into the local wake. */
2432
- seed_defer(stream, at) {
2433
- this._defer.set(stream, at);
2434
- this._defer.schedule();
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;
2435
2688
  }
2436
- get armed() {
2437
- return this._raised !== this._lowered;
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()]);
2438
2701
  }
2439
- get inflight() {
2440
- return this._inflight;
2702
+ /**
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.
2705
+ */
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();
2441
2718
  }
2442
- /** This lane's configured lease, or `undefined`; the shutdown grace basis. */
2443
- get lease_millis() {
2444
- return _optionalChain([this, 'access', _121 => _121._deps, 'access', _122 => _122.defaults, 'optionalAccess', _123 => _123.leaseMillis]);
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);
2445
2722
  }
2446
- get lane() {
2447
- return this._deps.lane;
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);
2731
+ }
2732
+ return pattern.test(stream);
2448
2733
  }
2449
- /**
2450
- * Drains every `cycleMs` while armed; the unref'd timer never holds the
2451
- * process. Called once, when the controller is built.
2452
- */
2453
- start(cycleMs) {
2454
- const run = this._deps.run_scoped;
2455
- const tick = async () => {
2456
- if (this.armed) await run(() => this.drain());
2457
- if (this._stopped) return;
2458
- this._worker = setTimeout(tick, cycleMs);
2459
- this._worker.unref();
2460
- };
2461
- this._worker = setTimeout(tick, cycleMs);
2462
- this._worker.unref();
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
+ }
2463
2744
  }
2464
- stop() {
2465
- this._stopped = true;
2466
- if (this._worker) {
2467
- clearTimeout(this._worker);
2468
- this._worker = void 0;
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
+ });
2875
+ }
2876
+ return { kind: "scanned", last_id, subscribed, marked, read };
2469
2877
  }
2470
- this._defer.stop();
2878
+ this._checkpoint = last_id;
2879
+ if (!stopped && found !== limit) this._lowered = raised;
2880
+ return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
2471
2881
  }
2472
- async drain(options = {}) {
2473
- if (!this.armed || this._stopped || this._inflight)
2474
- return EMPTY_DRAIN;
2475
- const d = _nullishCoalesce(this._deps.defaults, () => ( {}));
2476
- const streamLimit = _nullishCoalesce(_nullishCoalesce(d.streamLimit, () => ( options.streamLimit)), () => ( _chunkPRDX3HP6cjs.DEFAULT_STREAM_LIMIT));
2477
- const eventLimit = _nullishCoalesce(options.eventLimit, () => ( _chunkPRDX3HP6cjs.DEFAULT_EVENT_LIMIT));
2478
- const leaseMillis = _nullishCoalesce(_nullishCoalesce(d.leaseMillis, () => ( options.leaseMillis)), () => ( _chunkPRDX3HP6cjs.DEFAULT_LEASE_MILLIS));
2479
- if (this._deps.breaker.state(Date.now()) === "open")
2480
- return EMPTY_DRAIN;
2481
- const pass = this._pass(streamLimit, eventLimit, leaseMillis).finally(
2482
- () => {
2483
- this._inflight = void 0;
2484
- }
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
+ })
2485
2916
  );
2486
- this._inflight = pass;
2487
- return pass;
2488
2917
  }
2489
- // One claim → fetch → handle → ack pass. Never throws.
2490
- async _pass(streamLimit, eventLimit, leaseMillis) {
2918
+ /** Release the lease early by re-acquiring it for zero ms. Best-effort. */
2919
+ async release_correlation() {
2491
2920
  try {
2492
- const lagging = Math.ceil(streamLimit * this._ratio);
2493
- const leading = streamLimit - lagging;
2494
- const started = Date.now();
2495
- const raised = this._raised;
2496
- const cycle = await run_drain_cycle(this._deps, {
2497
- lagging,
2498
- leading,
2499
- eventLimit,
2500
- leaseMillis,
2501
- misrouted: this._misrouted,
2502
- 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
2503
2927
  });
2504
- if (!cycle) {
2505
- this._defer.prune(started);
2506
- this._deps.breaker.passed();
2507
- this._lowered = raised;
2508
- return EMPTY_DRAIN;
2509
- }
2510
- const { leased, fetched, handled, acked, blocked, closeable } = cycle;
2511
- trace_cycle(this._deps.logger, leased, fetched, handled, acked, blocked);
2512
- this._ratio = compute_lag_lead_ratio(handled, lagging, leading);
2513
- for (const lease of acked) this._defer.delete(lease.stream);
2514
- for (const lease of blocked) this._defer.delete(lease.stream);
2515
- for (const h of handled) {
2516
- const next = _nullishCoalesce(h.defer, () => ( h.next_attempt_at));
2517
- if (next !== void 0) this._defer.set(h.lease.stream, next);
2518
- }
2519
- if (acked.length) this._deps.on_acked(acked);
2520
- if (closeable.length) await this._deps.on_close(closeable);
2521
- this._deps.breaker.passed();
2522
- return { fetched, leased, acked, blocked };
2523
2928
  } catch (error) {
2524
- this._defer.set(
2525
- RETRY,
2526
- 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)))}`
2527
2931
  );
2528
- this._deps.breaker.failed(Date.now(), error);
2529
- return EMPTY_DRAIN;
2530
- } finally {
2531
- if (!this._stopped) this._defer.schedule();
2532
2932
  }
2533
2933
  }
2534
2934
  }, _class5);
@@ -2550,7 +2950,7 @@ function pii_gate(event, fields, predicate, actor) {
2550
2950
  const { pii, ...rest } = event;
2551
2951
  if (pii == null) {
2552
2952
  const shredded = { ...data };
2553
- for (const f of fields) shredded[f] = _chunkH6KVPVP4cjs.SHREDDED;
2953
+ for (const f of fields) shredded[f] = _chunkBCA423WPcjs.SHREDDED;
2554
2954
  return { ...rest, data: shredded };
2555
2955
  }
2556
2956
  const allowed = !!actor && !!predicate && predicate(event, actor);
@@ -2561,7 +2961,7 @@ function pii_gate(event, fields, predicate, actor) {
2561
2961
  };
2562
2962
  }
2563
2963
  const redacted = { ...data };
2564
- for (const f of fields) redacted[f] = _chunkH6KVPVP4cjs.REDACTED;
2964
+ for (const f of fields) redacted[f] = _chunkBCA423WPcjs.REDACTED;
2565
2965
  return { ...rest, data: redacted };
2566
2966
  }
2567
2967
  var IDENTITY_GATE = (event) => event;
@@ -2642,206 +3042,30 @@ function make_fold_handler(me, flush, config2, sensitive_fields) {
2642
3042
  cache2.delete(stream);
2643
3043
  fold = await first_sight(stream);
2644
3044
  }
2645
- if (event.id > fold.event_id) {
2646
- const reducer = me.patch[event.name];
2647
- fold.state = bare_patch(
2648
- me,
2649
- fold.state,
2650
- reducer(event, fold.state),
2651
- event
2652
- );
2653
- fold.version = event.version;
2654
- fold.event_id = event.id;
2655
- fold.patches++;
2656
- fold.dirty = true;
2657
- } else {
2658
- fold.dirty = true;
2659
- }
2660
- if (++folded_since_flush >= config2.flushEvery) {
2661
- await flush_dirty();
2662
- folded_since_flush = 0;
2663
- }
2664
- }
2665
- await flush_dirty();
2666
- };
2667
- Object.defineProperty(handler, FOLD_RESET, { value: () => cache2.clear() });
2668
- return handler;
2669
- }
2670
-
2671
- // src/internal/defer-config.ts
2672
-
2673
- var DeferDurationSchema = _zod.z.object({
2674
- days: _zod.z.number().positive().optional(),
2675
- hours: _zod.z.number().positive().optional(),
2676
- minutes: _zod.z.number().positive().optional()
2677
- }).strict().refine((d) => d.days != null || d.hours != null || d.minutes != null, {
2678
- message: "defer: a duration needs at least one of days, hours, or minutes"
2679
- });
2680
- var DeferWhenSchema = _zod.z.object({
2681
- after: DeferDurationSchema.optional(),
2682
- at: _zod.z.date().optional()
2683
- }).strict().refine((w) => w.after === void 0 !== (w.at === void 0), {
2684
- message: "defer: specify exactly one of `after` or `at`"
2685
- });
2686
- function duration_ms(d) {
2687
- return (_nullishCoalesce(d.days, () => ( 0))) * 864e5 + (_nullishCoalesce(d.hours, () => ( 0))) * 36e5 + (_nullishCoalesce(d.minutes, () => ( 0))) * 6e4;
2688
- }
2689
- function resolve_defer_at(when, event) {
2690
- const parsed = DeferWhenSchema.parse(when);
2691
- if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);
2692
- return parsed.at.getTime();
2693
- }
2694
- function assert_defer_when(when) {
2695
- DeferWhenSchema.parse(when);
2696
- }
2697
- function make_deferred(handler, schedule) {
2698
- const call = handler;
2699
- const deferred = async (event, stream, app) => {
2700
- const when = typeof schedule === "function" ? schedule(event) : schedule;
2701
- if (Date.now() < resolve_defer_at(when, event)) throw new (0, _chunkH6KVPVP4cjs.DeferSignal)(when);
2702
- return call(event, stream, app);
2703
- };
2704
- Object.defineProperty(deferred, "name", { value: handler.name });
2705
- return deferred;
2706
- }
2707
-
2708
- // src/internal/reaction-dispatch.ts
2709
- var CloseSignal = class extends Error {
2710
- /**
2711
- * Stream to close. Omitted → the reaction's own lease stream (a self-close).
2712
- * The synthesized autoclose reaction sets it to the aggregate stream, since
2713
- * its lease runs on a synthetic `__autoclose__` target.
2714
- */
2715
-
2716
- /** Optional archive callback to run while the stream is guarded. */
2717
-
2718
- /**
2719
- * Watermark to ack the requesting reaction to before the close runs. The
2720
- * close-cycle safety guard skips a stream whose subscriptions (matched by
2721
- * source) lag the head; the autoclose reaction's `source` is the aggregate,
2722
- * so it must advance its own watermark to the live head id it evaluated
2723
- * against — otherwise it blocks its own close. Defaults to the triggering
2724
- * event id when omitted.
2725
- */
2726
-
2727
- /**
2728
- * Windowed close: prune events older than this cutoff behind
2729
- * the closest safe snapshot instead of retiring the stream. Thrown by
2730
- * the autoclose reaction of a `.autocloses({ keep })` state; flows
2731
- * into {@link CloseTarget.before}. Omitted → a full close.
2732
- */
2733
-
2734
- constructor(opts) {
2735
- super("reaction requested close");
2736
- this.name = "CloseSignal";
2737
- this.stream = _optionalChain([opts, 'optionalAccess', _124 => _124.stream]);
2738
- this.archive = _optionalChain([opts, 'optionalAccess', _125 => _125.archive]);
2739
- this.at = _optionalChain([opts, 'optionalAccess', _126 => _126.at]);
2740
- this.before = _optionalChain([opts, 'optionalAccess', _127 => _127.before]);
2741
- }
2742
- };
2743
- function build_handle(deps) {
2744
- const { logger, reaction_scope } = deps;
2745
- return async (lease, payloads) => {
2746
- if (payloads.length === 0) return { lease, handled: 0, acked_at: lease.at };
2747
- const stream = lease.stream;
2748
- const last_index_of = /* @__PURE__ */ new Map();
2749
- for (let i = 0; i < payloads.length; i++)
2750
- last_index_of.set(payloads[i].event.id, i);
2751
- let at = lease.at;
2752
- let handled = 0;
2753
- if (lease.retry > 0)
2754
- logger.warn(
2755
- `Retrying ${stream}@${payloads.at(0).event.id} (${lease.retry}).`
2756
- );
2757
- for (let i = 0; i < payloads.length; i++) {
2758
- const payload = payloads[i];
2759
- const { event, handler } = payload;
2760
- try {
2761
- await reaction_scope.run(
2762
- event,
2763
- () => handler(event, stream, reaction_scope.app)
2764
- );
2765
- if (last_index_of.get(event.id) === i) {
2766
- at = event.id;
2767
- handled++;
2768
- }
2769
- } catch (error) {
2770
- if (error instanceof _chunkH6KVPVP4cjs.DeferSignal) {
2771
- let defer;
2772
- try {
2773
- defer = resolve_defer_at(error.when, event);
2774
- } catch (invalid) {
2775
- return finalize(
2776
- lease,
2777
- handled,
2778
- at,
2779
- invalid,
2780
- payload.options,
2781
- logger,
2782
- event.id
2783
- );
2784
- }
2785
- return { lease, handled, acked_at: at, defer };
2786
- }
2787
- if (error instanceof CloseSignal)
2788
- return {
2789
- lease,
2790
- handled: handled + 1,
2791
- // Advance to the live head the handler evaluated against (when
2792
- // provided) so the close-cycle guard sees this reaction caught up.
2793
- acked_at: _nullishCoalesce(error.at, () => ( event.id)),
2794
- // Close the signalled stream (the autoclose reaction's aggregate,
2795
- // which differs from its synthetic lease stream); a self-closing
2796
- // user reaction omits it and closes its own lease stream. A
2797
- // carried `before` makes it a windowed close (prune, not retire).
2798
- close: {
2799
- stream: _nullishCoalesce(error.stream, () => ( stream)),
2800
- archive: error.archive,
2801
- before: error.before
2802
- }
2803
- };
2804
- return finalize(
2805
- lease,
2806
- handled,
2807
- at,
2808
- error,
2809
- payload.options,
2810
- logger,
2811
- event.id
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
2812
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;
2813
3063
  }
2814
3064
  }
2815
- return finalize(lease, handled, at, void 0, payloads[0].options, logger);
2816
- };
2817
- }
2818
- function build_handle_batch(logger) {
2819
- return async (lease, payloads, batchHandler) => {
2820
- const stream = lease.stream;
2821
- const events = [];
2822
- const seen = /* @__PURE__ */ new Set();
2823
- for (const p of payloads) {
2824
- if (seen.has(p.event.id)) continue;
2825
- seen.add(p.event.id);
2826
- events.push(p.event);
2827
- }
2828
- const options = payloads[0].options;
2829
- if (lease.retry > 0)
2830
- logger.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);
2831
- try {
2832
- await batchHandler(events, stream);
2833
- return finalize(
2834
- lease,
2835
- events.length,
2836
- events.at(-1).id,
2837
- void 0,
2838
- options,
2839
- logger
2840
- );
2841
- } catch (error) {
2842
- return finalize(lease, 0, lease.at, error, options, logger);
2843
- }
3065
+ await flush_dirty();
2844
3066
  };
3067
+ Object.defineProperty(handler, FOLD_RESET, { value: () => cache2.clear() });
3068
+ return handler;
2845
3069
  }
2846
3070
 
2847
3071
  // src/internal/settle.ts
@@ -2882,7 +3106,7 @@ var SettleLoop = (_class6 = class {
2882
3106
  this._pending = true;
2883
3107
  return;
2884
3108
  }
2885
- const delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _128 => _128.debounceMs]), () => ( this._default_debounce_ms));
3109
+ const delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _146 => _146.debounceMs]), () => ( this._default_debounce_ms));
2886
3110
  const due = Date.now() + delay;
2887
3111
  if (this._timer) {
2888
3112
  if (due >= this._due) return;
@@ -3039,7 +3263,7 @@ var Act = (_class7 = class {
3039
3263
  // Lanes to arm per event; `"all"` when a dynamic resolver hides the lane.
3040
3264
 
3041
3265
 
3042
- __init27() {this._logger = _chunkPRDX3HP6cjs.log.call(void 0, )}
3266
+ __init27() {this._logger = _chunk4UWU5FANcjs.log.call(void 0, )}
3043
3267
  // This Act's ports: its own bag, or the singleton adapters.
3044
3268
 
3045
3269
  // Runs a body so internal `store()`/`cache()` calls resolve to `_ports`.
@@ -3061,9 +3285,9 @@ var Act = (_class7 = class {
3061
3285
  this._lanes = lanes;
3062
3286
  this._declared_lanes = ["default", ...lanes.map((l) => l.name)];
3063
3287
  validate_only_lanes(options.onlyLanes, this._declared_lanes);
3064
- this._ports = _nullishCoalesce(options.scoped, () => ( _chunkPRDX3HP6cjs.default_scope.call(void 0, )));
3288
+ this._ports = _nullishCoalesce(options.scoped, () => ( _chunk4UWU5FANcjs.default_scope.call(void 0, )));
3065
3289
  const ports = this._ports;
3066
- this._scoped = _chunkPRDX3HP6cjs.make_run_scoped.call(void 0, {
3290
+ this._scoped = _chunk4UWU5FANcjs.make_run_scoped.call(void 0, {
3067
3291
  // Getters, not a spread: the singletons resolve lazily, so a later
3068
3292
  // `store(...)` / `cache(...)` still takes effect.
3069
3293
  get store() {
@@ -3073,14 +3297,14 @@ var Act = (_class7 = class {
3073
3297
  return ports.cache;
3074
3298
  },
3075
3299
  // Parsed per build, so a bad window throws on every build.
3076
- autoclose_window: _chunkPRDX3HP6cjs.resolveAutocloseConfig.call(void 0, options).autocloseWindow
3300
+ autoclose_window: _chunk4UWU5FANcjs.resolveAutocloseConfig.call(void 0, options).autocloseWindow
3077
3301
  });
3078
3302
  this._correlator = _nullishCoalesce(options.correlator, () => ( default_correlator));
3079
3303
  this._es = build_es(this._logger, this._correlator, patch_fn);
3080
3304
  this._cd = build_drain(this._logger);
3081
3305
  const handle = build_handle({
3082
3306
  logger: this._logger,
3083
- reaction_scope: _chunkPRDX3HP6cjs.make_reaction_scope.call(void 0, {
3307
+ reaction_scope: _chunk4UWU5FANcjs.make_reaction_scope.call(void 0, {
3084
3308
  do: this.do.bind(this),
3085
3309
  load: this.load.bind(this),
3086
3310
  query: this.query.bind(this),
@@ -3110,12 +3334,12 @@ var Act = (_class7 = class {
3110
3334
  this._ports.store,
3111
3335
  options.listen !== false
3112
3336
  );
3113
- _chunkPRDX3HP6cjs.register_weak_disposer.call(void 0, new WeakRef(this), (self) => self.shutdown());
3337
+ _chunk4UWU5FANcjs.register_weak_disposer.call(void 0, new WeakRef(this), (self) => self.shutdown());
3114
3338
  }
3115
3339
  // Shared by drain, settle and autoclose; bad knobs throw at build.
3116
3340
  _build_breaker(options) {
3117
3341
  return new CircuitBreaker(
3118
- _chunkPRDX3HP6cjs.resolveCircuitBreakerConfig.call(void 0, options.circuitBreaker),
3342
+ _chunk4UWU5FANcjs.resolveCircuitBreakerConfig.call(void 0, options.circuitBreaker),
3119
3343
  {
3120
3344
  on_error: (error, circuit) => this._emit_error(error, circuit),
3121
3345
  // When the cooldown elapses, settle once: its scan or claim is the
@@ -3127,7 +3351,7 @@ var Act = (_class7 = class {
3127
3351
  // Apps that declare no lanes pass no lane filter to `claim`.
3128
3352
  _build_drain_controllers(options, lanes, handle, handle_batch) {
3129
3353
  const all_lanes = this._declared_lanes;
3130
- const only_set = _optionalChain([options, 'access', _129 => _129.onlyLanes, 'optionalAccess', _130 => _130.length]) ? new Set(options.onlyLanes) : void 0;
3354
+ const only_set = _optionalChain([options, 'access', _147 => _147.onlyLanes, 'optionalAccess', _148 => _148.length]) ? new Set(options.onlyLanes) : void 0;
3131
3355
  const active_lanes = only_set ? all_lanes.filter((n) => only_set.has(n)) : all_lanes;
3132
3356
  const single_default_lane = lanes.length === 0;
3133
3357
  const controllers = /* @__PURE__ */ new Map();
@@ -3149,7 +3373,7 @@ var Act = (_class7 = class {
3149
3373
  try {
3150
3374
  await this._run_close(targets);
3151
3375
  } catch (error) {
3152
- if (error instanceof _chunkH6KVPVP4cjs.StoreError) throw error;
3376
+ if (error instanceof _chunkBCA423WPcjs.StoreError) throw error;
3153
3377
  this._logger.error(
3154
3378
  error,
3155
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.`
@@ -3164,7 +3388,7 @@ var Act = (_class7 = class {
3164
3388
  leaseMillis: cfg.leaseMillis
3165
3389
  }
3166
3390
  });
3167
- if (_optionalChain([cfg, 'optionalAccess', _131 => _131.cycleMs]) !== void 0 && this._drain)
3391
+ if (_optionalChain([cfg, 'optionalAccess', _149 => _149.cycleMs]) !== void 0 && this._drain)
3168
3392
  controller.start(cfg.cycleMs);
3169
3393
  controllers.set(name, controller);
3170
3394
  }
@@ -3183,7 +3407,7 @@ var Act = (_class7 = class {
3183
3407
  // Audit deps, built after the controllers so the lane set is final.
3184
3408
  _build_audit_deps() {
3185
3409
  return {
3186
- store: _chunkPRDX3HP6cjs.store,
3410
+ store: _chunk4UWU5FANcjs.store,
3187
3411
  event_to_state: this._event_to_state,
3188
3412
  // Declared lanes, not this process's controllers: a lane another
3189
3413
  // worker drains is not `unknown-lane`.
@@ -3196,7 +3420,7 @@ var Act = (_class7 = class {
3196
3420
  registry: this.registry,
3197
3421
  static_targets: classification.static_targets,
3198
3422
  cd: this._cd,
3199
- max_subscribed_streams: _nullishCoalesce(options.maxSubscribedStreams, () => ( _chunkH6KVPVP4cjs.DEFAULT_MAX_SUBSCRIBED_STREAMS)),
3423
+ max_subscribed_streams: _nullishCoalesce(options.maxSubscribedStreams, () => ( _chunkBCA423WPcjs.DEFAULT_MAX_SUBSCRIBED_STREAMS)),
3200
3424
  // Declared lanes (not active ones): a lane another process claims is
3201
3425
  // still a valid destination.
3202
3426
  declared_lanes: new Set(this._declared_lanes),
@@ -3212,10 +3436,10 @@ var Act = (_class7 = class {
3212
3436
  // Cold start: an idle deferred stream still fires on time after a restart.
3213
3437
  async _seed_persisted_defers() {
3214
3438
  const now = Date.now();
3215
- await walk_streams(_chunkPRDX3HP6cjs.store.call(void 0, ), (pos) => {
3439
+ await walk_streams(_chunk4UWU5FANcjs.store.call(void 0, ), (pos) => {
3216
3440
  if (pos.deferred_at === void 0 || pos.deferred_at <= now) return;
3217
3441
  const controller = this._drain_controllers.get(_nullishCoalesce(pos.lane, () => ( "default")));
3218
- _optionalChain([controller, 'optionalAccess', _132 => _132.seed_defer, 'call', _133 => _133(pos.stream, pos.deferred_at)]);
3442
+ _optionalChain([controller, 'optionalAccess', _150 => _150.seed_defer, 'call', _151 => _151(pos.stream, pos.deferred_at)]);
3219
3443
  });
3220
3444
  }
3221
3445
  _build_settle(options) {
@@ -3228,7 +3452,7 @@ var Act = (_class7 = class {
3228
3452
  on_settled: (drain) => this.emit("settled", drain),
3229
3453
  breaker: this._breaker
3230
3454
  },
3231
- _nullishCoalesce(options.settleDebounceMs, () => ( _chunkH6KVPVP4cjs.DEFAULT_SETTLE_DEBOUNCE_MS))
3455
+ _nullishCoalesce(options.settleDebounceMs, () => ( _chunkBCA423WPcjs.DEFAULT_SETTLE_DEBOUNCE_MS))
3232
3456
  );
3233
3457
  }
3234
3458
 
@@ -3248,7 +3472,7 @@ var Act = (_class7 = class {
3248
3472
  */
3249
3473
  shutdown(options) {
3250
3474
  if (!this._shutdown_promise) {
3251
- _chunkPRDX3HP6cjs.resolveShutdownConfig.call(void 0, options);
3475
+ _chunk4UWU5FANcjs.resolveShutdownConfig.call(void 0, options);
3252
3476
  this._shutdown_promise = (async () => {
3253
3477
  this.stop_correlations();
3254
3478
  this._settle.stop(true);
@@ -3256,7 +3480,7 @@ var Act = (_class7 = class {
3256
3480
  for (const c of this._drain_controllers.values()) c.stop();
3257
3481
  const disposer = await this._notify_disposer;
3258
3482
  if (disposer) await disposer();
3259
- await this._await_inflight(_optionalChain([options, 'optionalAccess', _134 => _134.graceMs]));
3483
+ await this._await_inflight(_optionalChain([options, 'optionalAccess', _152 => _152.graceMs]));
3260
3484
  await this._scoped(() => this._correlate.release_correlation());
3261
3485
  this._emitter.removeAllListeners();
3262
3486
  })();
@@ -3266,10 +3490,10 @@ var Act = (_class7 = class {
3266
3490
  // The largest `leaseMillis` among lanes with a cycle in flight (the
3267
3491
  // default for none or 0, and for a running settle), capped.
3268
3492
  _derive_grace_ms(running, settling) {
3269
- let max = settling ? _chunkPRDX3HP6cjs.DEFAULT_LEASE_MILLIS : 0;
3493
+ let max = settling ? _chunk4UWU5FANcjs.DEFAULT_LEASE_MILLIS : 0;
3270
3494
  for (const c of running)
3271
- max = Math.max(max, c.lease_millis || _chunkPRDX3HP6cjs.DEFAULT_LEASE_MILLIS);
3272
- return Math.min(max, _chunkPRDX3HP6cjs.MAX_SHUTDOWN_GRACE_MS);
3495
+ max = Math.max(max, c.lease_millis || _chunk4UWU5FANcjs.DEFAULT_LEASE_MILLIS);
3496
+ return Math.min(max, _chunk4UWU5FANcjs.MAX_SHUTDOWN_GRACE_MS);
3273
3497
  }
3274
3498
  async _await_inflight(grace_ms) {
3275
3499
  const running = [...this._drain_controllers.values()].filter(
@@ -3352,8 +3576,8 @@ var Act = (_class7 = class {
3352
3576
  * @see {@link ValidationError}, {@link PreconditionError}, {@link ConcurrencyError}
3353
3577
  */
3354
3578
  async do(action2, target, payload, options) {
3355
- const reacting_to = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _135 => _135.reactingTo]), () => ( _chunkPRDX3HP6cjs.current_reacting.call(void 0, )));
3356
- const do_options = reacting_to === _optionalChain([options, 'optionalAccess', _136 => _136.reactingTo]) ? options : { ...options, reactingTo: reacting_to };
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 };
3357
3581
  return this._scoped(async () => {
3358
3582
  const snapshots = await this._es.action(
3359
3583
  this.registry.actions[action2],
@@ -3418,11 +3642,11 @@ var Act = (_class7 = class {
3418
3642
  return this._scoped(async () => {
3419
3643
  let first;
3420
3644
  let last;
3421
- const count = await _chunkPRDX3HP6cjs.store.call(void 0, ).query((e) => {
3645
+ const count = await _chunk4UWU5FANcjs.store.call(void 0, ).query((e) => {
3422
3646
  const gated = this.registry.query_gate(e.name)(e);
3423
3647
  if (!first) first = gated;
3424
3648
  last = gated;
3425
- _optionalChain([callback, 'optionalCall', _137 => _137(gated)]);
3649
+ _optionalChain([callback, 'optionalCall', _155 => _155(gated)]);
3426
3650
  }, query);
3427
3651
  return { first, last, count };
3428
3652
  });
@@ -3448,7 +3672,7 @@ var Act = (_class7 = class {
3448
3672
  async query_array(query) {
3449
3673
  return this._scoped(async () => {
3450
3674
  const events = [];
3451
- await _chunkPRDX3HP6cjs.store.call(void 0, ).query((e) => {
3675
+ await _chunk4UWU5FANcjs.store.call(void 0, ).query((e) => {
3452
3676
  events.push(this.registry.query_gate(e.name)(e));
3453
3677
  }, query);
3454
3678
  return events;
@@ -3468,14 +3692,14 @@ var Act = (_class7 = class {
3468
3692
  */
3469
3693
  async forget(stream) {
3470
3694
  return this._scoped(async () => {
3471
- const s = _chunkPRDX3HP6cjs.store.call(void 0, );
3695
+ const s = _chunk4UWU5FANcjs.store.call(void 0, );
3472
3696
  if (!s.forget_pii) {
3473
3697
  throw new Error(
3474
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).`
3475
3699
  );
3476
3700
  }
3477
3701
  const eventCount = await s.forget_pii(stream);
3478
- await _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(stream);
3702
+ await _chunk4UWU5FANcjs.cache.call(void 0, ).invalidate(stream);
3479
3703
  if (eventCount > 0) {
3480
3704
  this.emit("forgotten", { stream, at: /* @__PURE__ */ new Date(), eventCount });
3481
3705
  }
@@ -3509,7 +3733,7 @@ var Act = (_class7 = class {
3509
3733
  * @see {@link correlate} for dynamic stream discovery
3510
3734
  */
3511
3735
  async drain(options = {}) {
3512
- _chunkPRDX3HP6cjs.resolveDrainConfig.call(void 0, options);
3736
+ _chunk4UWU5FANcjs.resolveDrainConfig.call(void 0, options);
3513
3737
  if (!this._drain)
3514
3738
  return { fetched: [], leased: [], acked: [], blocked: [] };
3515
3739
  return this._scoped(() => this._drain_all(options));
@@ -3547,7 +3771,7 @@ var Act = (_class7 = class {
3547
3771
  }
3548
3772
  if (to_arm.size === 0) return false;
3549
3773
  this._correlate.arm();
3550
- for (const lane of to_arm) _optionalChain([this, 'access', _138 => _138._drain_controllers, 'access', _139 => _139.get, 'call', _140 => _140(lane), 'optionalAccess', _141 => _141.arm, 'call', _142 => _142()]);
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()]);
3551
3775
  return true;
3552
3776
  }
3553
3777
  // In parallel, so a slow lane never holds up a fast one.
@@ -3689,9 +3913,9 @@ var Act = (_class7 = class {
3689
3913
  */
3690
3914
  async reset(input) {
3691
3915
  return this._scoped(async () => {
3692
- const count = await _chunkPRDX3HP6cjs.store.call(void 0, ).reset(input);
3916
+ const count = await _chunk4UWU5FANcjs.store.call(void 0, ).reset(input);
3693
3917
  for (const handler of this._batch_handlers.values())
3694
- _optionalChain([handler, 'access', _143 => _143[FOLD_RESET], 'optionalCall', _144 => _144()]);
3918
+ _optionalChain([handler, 'access', _161 => _161[FOLD_RESET], 'optionalCall', _162 => _162()]);
3695
3919
  if (count > 0) {
3696
3920
  this._wake();
3697
3921
  }
@@ -3725,7 +3949,7 @@ var Act = (_class7 = class {
3725
3949
  */
3726
3950
  async unblock(input) {
3727
3951
  return this._scoped(async () => {
3728
- const count = await _chunkPRDX3HP6cjs.store.call(void 0, ).unblock(input);
3952
+ const count = await _chunk4UWU5FANcjs.store.call(void 0, ).unblock(input);
3729
3953
  if (count > 0) {
3730
3954
  this._wake();
3731
3955
  }
@@ -3780,7 +4004,7 @@ var Act = (_class7 = class {
3780
4004
  return { ...partial, duration_ms: Date.now() - started };
3781
4005
  }
3782
4006
  const target = _nullishCoalesce(sink, () => ( (() => {
3783
- const s = _chunkPRDX3HP6cjs.store.call(void 0, );
4007
+ const s = _chunk4UWU5FANcjs.store.call(void 0, );
3784
4008
  if (!s.restore) throw new Error("adapter has no restore capability");
3785
4009
  return s;
3786
4010
  })()));
@@ -3826,11 +4050,11 @@ var Act = (_class7 = class {
3826
4050
  async blocked_streams(options) {
3827
4051
  return this._scoped(async () => {
3828
4052
  const positions = [];
3829
- await _chunkPRDX3HP6cjs.store.call(void 0, ).query_streams(
4053
+ await _chunk4UWU5FANcjs.store.call(void 0, ).query_streams(
3830
4054
  (p) => {
3831
4055
  positions.push(p);
3832
4056
  },
3833
- { blocked: true, after: _optionalChain([options, 'optionalAccess', _145 => _145.after]), limit: _optionalChain([options, 'optionalAccess', _146 => _146.limit]) }
4057
+ { blocked: true, after: _optionalChain([options, 'optionalAccess', _163 => _163.after]), limit: _optionalChain([options, 'optionalAccess', _164 => _164.limit]) }
3834
4058
  );
3835
4059
  return positions;
3836
4060
  });
@@ -3878,7 +4102,7 @@ var Act = (_class7 = class {
3878
4102
  * @see {@link Store.prioritize} for the underlying primitive
3879
4103
  */
3880
4104
  async prioritize(filter, priority) {
3881
- return this._scoped(() => _chunkPRDX3HP6cjs.store.call(void 0, ).prioritize(filter, priority));
4105
+ return this._scoped(() => _chunk4UWU5FANcjs.store.call(void 0, ).prioritize(filter, priority));
3882
4106
  }
3883
4107
  // Shared by `close()` and reaction-requested closes.
3884
4108
  async _run_close(targets) {
@@ -3958,222 +4182,11 @@ var Act = (_class7 = class {
3958
4182
  * @see {@link correlate} for manual correlation
3959
4183
  */
3960
4184
  settle(options) {
3961
- _chunkPRDX3HP6cjs.resolveSettleConfig.call(void 0, _nullishCoalesce(options, () => ( {})));
4185
+ _chunk4UWU5FANcjs.resolveSettleConfig.call(void 0, _nullishCoalesce(options, () => ( {})));
3962
4186
  this._schedule(options);
3963
4187
  }
3964
4188
  }, _class7);
3965
4189
 
3966
- // src/internal/autoclose-policy.ts
3967
-
3968
- var DAY_MS = 864e5;
3969
- var MIN_AFTER_DAYS = 1 / 1440;
3970
- var MIN_KEEP_DAYS = 1;
3971
- function days_after(date, days) {
3972
- return new Date(date.getTime() + days * DAY_MS);
3973
- }
3974
- function days_before_now(days) {
3975
- return new Date(Date.now() - days * DAY_MS);
3976
- }
3977
- var window_schema = (field, min_days, floor) => _zod.z.object({
3978
- days: _zod.z.number({ message: `autocloses: ${field}.days must be a number` }).positive(`autocloses: ${field}.days must be > 0`)
3979
- }).refine((o) => o.days >= min_days, {
3980
- message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`
3981
- });
3982
- var AfterSchema = window_schema("after", MIN_AFTER_DAYS, "one minute");
3983
- var KeepSchema = window_schema("keep", MIN_KEEP_DAYS, "one day");
3984
- var IsSchema = _zod.z.union([
3985
- _zod.z.string().min(1, "autocloses: is must be a non-empty event name"),
3986
- _zod.z.array(
3987
- _zod.z.string().min(1, "autocloses: is entries must be non-empty event names")
3988
- ).min(1, "autocloses: is must include at least one event name").readonly()
3989
- ]);
3990
- 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");
3991
- var OrBlockSchema = _zod.z.object({
3992
- after: AfterSchema.optional(),
3993
- is: IsSchema.optional(),
3994
- reaches: ReachesSchema.optional()
3995
- }).strict().refine(
3996
- (o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0,
3997
- {
3998
- message: "autocloses: `or` block must include at least one of after / is / reaches"
3999
- }
4000
- );
4001
- var AutoclosePolicySchema = _zod.z.object({
4002
- after: AfterSchema.optional(),
4003
- is: IsSchema.optional(),
4004
- reaches: ReachesSchema.optional(),
4005
- or: OrBlockSchema.optional(),
4006
- keep: KeepSchema.optional()
4007
- }).strict().refine(
4008
- (o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0 || o.or !== void 0 || o.keep !== void 0,
4009
- {
4010
- message: "autocloses: at least one of after / is / reaches / or / keep must be specified \u2014 empty `{}` is a misconfiguration"
4011
- }
4012
- );
4013
- function compile_after(after) {
4014
- return (_stream, head) => days_after(head.created, after.days) <= /* @__PURE__ */ new Date();
4015
- }
4016
- function compile_is(is) {
4017
- const set = new Set(typeof is === "string" ? [is] : is);
4018
- return (_stream, head) => set.has(head.name);
4019
- }
4020
- function compile_reaches(reaches) {
4021
- return (_stream, _head, count) => count >= reaches;
4022
- }
4023
- function policy_min_after_days(options) {
4024
- const parsed = AutoclosePolicySchema.parse(options);
4025
- const windows = [];
4026
- if (parsed.after) windows.push(parsed.after.days);
4027
- if (_optionalChain([parsed, 'access', _147 => _147.or, 'optionalAccess', _148 => _148.after])) windows.push(parsed.or.after.days);
4028
- return windows.length ? Math.min(...windows) : void 0;
4029
- }
4030
- function policy_after_windows(options) {
4031
- const parsed = AutoclosePolicySchema.parse(options);
4032
- return [parsed.after, _optionalChain([parsed, 'access', _149 => _149.or, 'optionalAccess', _150 => _150.after])].flatMap((w) => w ? [w.days] : []);
4033
- }
4034
- function policy_keep_days(options) {
4035
- const parsed = AutoclosePolicySchema.parse(options);
4036
- return _optionalChain([parsed, 'access', _151 => _151.keep, 'optionalAccess', _152 => _152.days]);
4037
- }
4038
- function compile_autoclose_policy(options) {
4039
- const parsed = AutoclosePolicySchema.parse(options);
4040
- const and_preds = [];
4041
- if (parsed.after) and_preds.push(compile_after(parsed.after));
4042
- if (parsed.is) and_preds.push(compile_is(parsed.is));
4043
- if (parsed.reaches) and_preds.push(compile_reaches(parsed.reaches));
4044
- const or_preds = [];
4045
- if (parsed.or) {
4046
- if (parsed.or.after) or_preds.push(compile_after(parsed.or.after));
4047
- if (parsed.or.is) or_preds.push(compile_is(parsed.or.is));
4048
- if (parsed.or.reaches) or_preds.push(compile_reaches(parsed.or.reaches));
4049
- }
4050
- return (stream, head, count) => {
4051
- if (and_preds.length > 0 && and_preds.every((p) => p(stream, head, count))) {
4052
- return true;
4053
- }
4054
- if (or_preds.some((p) => p(stream, head, count))) {
4055
- return true;
4056
- }
4057
- return false;
4058
- };
4059
- }
4060
-
4061
- // src/internal/autoclose-window.ts
4062
- function hour_in_zone(now, timeZone) {
4063
- const parts = new Intl.DateTimeFormat("en-US", {
4064
- timeZone,
4065
- hour: "2-digit",
4066
- hourCycle: "h23"
4067
- }).formatToParts(now);
4068
- return Number(_optionalChain([parts, 'access', _153 => _153.find, 'call', _154 => _154((p) => p.type === "hour"), 'optionalAccess', _155 => _155.value]));
4069
- }
4070
- function hour_in_range(hour, start, end) {
4071
- return start < end ? hour >= start && hour < end : hour >= start || hour < end;
4072
- }
4073
- function is_dst_gap_open(now, timeZone, start) {
4074
- const hour = hour_in_zone(now, timeZone);
4075
- if (hour <= start) return false;
4076
- const prev = hour_in_zone(new Date(now.getTime() - 36e5), timeZone);
4077
- return prev === start - 1 && hour === start + 1;
4078
- }
4079
- function in_autoclose_window(window, now) {
4080
- if (!window) return true;
4081
- const hour = hour_in_zone(now, window.timeZone);
4082
- return hour_in_range(hour, window.start, window.end) || is_dst_gap_open(now, window.timeZone, window.start);
4083
- }
4084
- function next_window_open(window, now) {
4085
- const start_ms = now.getTime();
4086
- for (let h = 0; h <= 48; h++) {
4087
- const candidate = new Date(start_ms + h * 36e5);
4088
- if (hour_in_zone(candidate, window.timeZone) === window.start)
4089
- return candidate;
4090
- const boundary = new Date(
4091
- candidate.getTime() - candidate.getTime() % 36e5
4092
- );
4093
- if (boundary.getTime() >= start_ms && is_dst_gap_open(boundary, window.timeZone, window.start))
4094
- return boundary;
4095
- }
4096
- return new Date(start_ms + 864e5);
4097
- }
4098
-
4099
- // src/internal/autoclose-reaction.ts
4100
- var AUTOCLOSE_TARGET_PREFIX = "__autoclose__:";
4101
- function synthesize_autoclose_reactions(registry, states, read_window) {
4102
- for (const st of states.values()) {
4103
- const predicate = st.autoclose;
4104
- if (!predicate) continue;
4105
- const after_windows = st.autoclose_after_windows;
4106
- const keep_days = st.autoclose_keep_days;
4107
- const archiver = st.archive;
4108
- const reaction = {
4109
- // Run on a SYNTHETIC stream — `source` is the aggregate, `target` is a
4110
- // per-aggregate `__autoclose__` key — so the autoclose reaction never
4111
- // shares a watermark with the aggregate's own reactions. A shared
4112
- // watermark would let autoclose's defer short-circuit the aggregate's
4113
- // other reactions (the "a defer affects all reactions on a stream"
4114
- // hazard). The close still targets the aggregate (`source`).
4115
- // A stream name with a regex metacharacter would read as a pattern, and a
4116
- // store may refuse it at subscribe, stopping every reaction. Such a stream
4117
- // has no autoclose: `app.close` still closes it.
4118
- resolver: (e) => _chunkPRDX3HP6cjs.is_literal_source.call(void 0, e.stream) ? {
4119
- target: `${AUTOCLOSE_TARGET_PREFIX}${e.stream}`,
4120
- source: e.stream
4121
- } : void 0,
4122
- // Never block on autoclose: a transient query/store error should retry,
4123
- // not quarantine the synthetic stream.
4124
- options: { blockOnError: false, maxRetries: _chunkPRDX3HP6cjs.DEFAULT_MAX_RETRIES },
4125
- handler: async (event) => {
4126
- const aggregate = event.stream;
4127
- const window = read_window();
4128
- if (!in_autoclose_window(window, /* @__PURE__ */ new Date()))
4129
- throw new (0, _chunkH6KVPVP4cjs.DeferSignal)({ at: next_window_open(window, /* @__PURE__ */ new Date()) });
4130
- const stats = await _chunkPRDX3HP6cjs.store.call(void 0, ).query_stats([aggregate], {
4131
- count: true,
4132
- tail: keep_days !== void 0 ? true : void 0,
4133
- exclude: [_chunkH6KVPVP4cjs.TOMBSTONE_EVENT, _chunkH6KVPVP4cjs.SNAP_EVENT]
4134
- });
4135
- const entry = stats.get(aggregate);
4136
- if (!entry) return;
4137
- const head = entry.head;
4138
- if (predicate(aggregate, head, entry.count))
4139
- throw new CloseSignal({
4140
- stream: aggregate,
4141
- archive: archiver ? () => archiver(aggregate, head) : void 0,
4142
- // Ack this reaction's own watermark to the live head so the
4143
- // close-cycle guard (which matches subscriptions by source =
4144
- // aggregate) sees it caught up instead of blocking its own close.
4145
- at: head.id
4146
- });
4147
- if (keep_days !== void 0) {
4148
- const cutoff = days_before_now(keep_days);
4149
- if (entry.tail.created < cutoff)
4150
- throw new CloseSignal({
4151
- stream: aggregate,
4152
- before: cutoff,
4153
- archive: archiver ? () => archiver(aggregate, head, cutoff) : void 0,
4154
- at: head.id
4155
- });
4156
- }
4157
- const dues = [];
4158
- for (const days of after_windows)
4159
- dues.push(days_after(head.created, days));
4160
- if (keep_days !== void 0)
4161
- dues.push(days_after(entry.tail.created, keep_days));
4162
- const future = dues.map((d) => d.getTime()).filter((t) => t > Date.now());
4163
- if (future.length)
4164
- throw new (0, _chunkH6KVPVP4cjs.DeferSignal)({ at: new Date(Math.min(...future)) });
4165
- }
4166
- };
4167
- const key = `__autoclose_${st.name}`;
4168
- for (const event_name of Object.keys(st.events)) {
4169
- _optionalChain([registry, 'access', _156 => _156.events, 'access', _157 => _157[event_name], 'optionalAccess', _158 => _158.reactions, 'access', _159 => _159.set, 'call', _160 => _160(
4170
- key,
4171
- reaction
4172
- )]);
4173
- }
4174
- }
4175
- }
4176
-
4177
4190
  // src/builders/merge.ts
4178
4191
 
4179
4192
  function base_type_name(zodType) {
@@ -4367,9 +4380,9 @@ var _this_ = ({ stream }) => ({
4367
4380
 
4368
4381
  // src/builders/builder-utils.ts
4369
4382
  function register_lane(config2, lanes) {
4370
- _chunkPRDX3HP6cjs.resolveLaneConfig.call(void 0, config2);
4371
- if (config2.name === _chunkH6KVPVP4cjs.DEFAULT_LANE)
4372
- throw new Error(`Lane "${_chunkH6KVPVP4cjs.DEFAULT_LANE}" is reserved`);
4383
+ _chunk4UWU5FANcjs.resolveLaneConfig.call(void 0, config2);
4384
+ if (config2.name === _chunkBCA423WPcjs.DEFAULT_LANE)
4385
+ throw new Error(`Lane "${_chunkBCA423WPcjs.DEFAULT_LANE}" is reserved`);
4373
4386
  const existing = lanes.find((l) => l.name === config2.name);
4374
4387
  if (!existing) return void lanes.push(config2);
4375
4388
  if (existing.leaseMillis !== config2.leaseMillis || existing.streamLimit !== config2.streamLimit || existing.cycleMs !== config2.cycleMs)
@@ -4411,10 +4424,10 @@ function reaction_on(event, events, builder) {
4411
4424
  // Validate the whole bag at the declaration site so a bad
4412
4425
  // `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,
4413
4426
  // not a NaN gate on the first retry.
4414
- options: _chunkPRDX3HP6cjs.resolveReactionConfig.call(void 0, {
4415
- blockOnError: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _161 => _161.blockOnError]), () => ( _chunkPRDX3HP6cjs.DEFAULT_BLOCK_ON_ERROR)),
4416
- maxRetries: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _162 => _162.maxRetries]), () => ( _chunkPRDX3HP6cjs.DEFAULT_MAX_RETRIES)),
4417
- backoff: _optionalChain([options, 'optionalAccess', _163 => _163.backoff])
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])
4418
4431
  })
4419
4432
  };
4420
4433
  },
@@ -4433,25 +4446,47 @@ function reaction_on(event, events, builder) {
4433
4446
 
4434
4447
  // src/internal/date-reviver.ts
4435
4448
 
4436
- function variant_schema(schema) {
4437
- const shape = _optionalChain([_chunkH6KVPVP4cjs.def_of.call(void 0, schema), 'optionalAccess', _164 => _164.shape]);
4449
+ function variant_schema(schema, walk) {
4450
+ const shape = _optionalChain([_chunkBCA423WPcjs.def_of.call(void 0, schema), 'optionalAccess', _168 => _168.shape]);
4438
4451
  if (!shape) {
4439
- const dates = date_reviver_schema(schema);
4452
+ const dates = walk(schema);
4440
4453
  return { schema: _nullishCoalesce(dates, () => ( schema)), dated: !!dates };
4441
4454
  }
4442
4455
  const next = {};
4443
4456
  let dated = false;
4444
4457
  for (const [key, field] of Object.entries(shape)) {
4445
- const dates = date_reviver_schema(field);
4458
+ const dates = walk(field);
4446
4459
  if (dates) dated = true;
4447
4460
  next[key] = (_nullishCoalesce(dates, () => ( field))).optional();
4448
4461
  }
4449
4462
  return { schema: _zod.z.looseObject(next), dated };
4450
4463
  }
4451
4464
  function date_reviver_schema(schema) {
4452
- const def = _chunkH6KVPVP4cjs.def_of.call(void 0, schema);
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);
4453
4488
  if (!def) return void 0;
4454
- const inner = () => date_reviver_schema(def.innerType);
4489
+ const inner = () => walk(def.innerType);
4455
4490
  switch (def.type) {
4456
4491
  case "date":
4457
4492
  return _zod.z.coerce.date();
@@ -4460,39 +4495,48 @@ function date_reviver_schema(schema) {
4460
4495
  if (!shape) return void 0;
4461
4496
  const dated = {};
4462
4497
  for (const [key, field] of Object.entries(shape)) {
4463
- const dates = date_reviver_schema(field);
4498
+ const dates = walk(field);
4464
4499
  if (dates) dated[key] = dates.optional();
4465
4500
  }
4466
4501
  return Object.keys(dated).length ? _zod.z.looseObject(dated) : void 0;
4467
4502
  }
4468
4503
  case "array": {
4469
- const element = date_reviver_schema(def.element);
4504
+ const element = walk(def.element);
4470
4505
  return element && _zod.z.array(element);
4471
4506
  }
4472
4507
  case "tuple": {
4473
- const items = def.items.map((i) => date_reviver_schema(i));
4508
+ const items = def.items.map((i) => walk(i));
4474
4509
  return items.some(Boolean) ? _zod.z.tuple(items.map((i) => _nullishCoalesce(i, () => ( _zod.z.unknown())))) : void 0;
4475
4510
  }
4476
4511
  case "record": {
4477
- const value = date_reviver_schema(def.valueType);
4512
+ const value = walk(def.valueType);
4478
4513
  return value && _zod.z.record(_zod.z.string(), value);
4479
4514
  }
4480
4515
  case "union": {
4481
- const variants = def.options.map(variant_schema);
4516
+ const variants = def.options.map(
4517
+ (o) => variant_schema(o, walk)
4518
+ );
4482
4519
  return variants.some((v) => v.dated) ? _zod.z.union(variants.map((v) => v.schema)) : void 0;
4483
4520
  }
4484
4521
  case "nullable":
4485
- return _optionalChain([inner, 'call', _165 => _165(), 'optionalAccess', _166 => _166.nullable, 'call', _167 => _167()]);
4522
+ return _optionalChain([inner, 'call', _169 => _169(), 'optionalAccess', _170 => _170.nullable, 'call', _171 => _171()]);
4486
4523
  case "pipe":
4487
- return date_reviver_schema(def.out);
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
+ }
4488
4532
  default:
4489
- return _chunkH6KVPVP4cjs.inner_of.call(void 0, def) ? inner() : void 0;
4533
+ return _chunkBCA423WPcjs.inner_of.call(void 0, def) ? inner() : void 0;
4490
4534
  }
4491
4535
  }
4492
4536
 
4493
4537
  // src/builders/event-builder.ts
4494
4538
  function event_tags(schema) {
4495
- const pii = _chunkH6KVPVP4cjs.pii_schemas.call(void 0, schema);
4539
+ const pii = _chunkBCA423WPcjs.pii_schemas.call(void 0, schema);
4496
4540
  const pii_dates = {};
4497
4541
  for (const [key, field] of Object.entries(pii)) {
4498
4542
  const dates = date_reviver_schema(field);
@@ -4530,7 +4574,7 @@ function make_event_reader(tags, disclosure, predicate = null) {
4530
4574
  });
4531
4575
  }
4532
4576
  function build_events(registry, states, lanes, owners) {
4533
- const declared = /* @__PURE__ */ new Set([_chunkH6KVPVP4cjs.DEFAULT_LANE, ...lanes.map((l) => l.name)]);
4577
+ const declared = /* @__PURE__ */ new Set([_chunkBCA423WPcjs.DEFAULT_LANE, ...lanes.map((l) => l.name)]);
4534
4578
  const lane_errors = [];
4535
4579
  const tags = /* @__PURE__ */ new Map();
4536
4580
  const sensitive2 = /* @__PURE__ */ new Map();
@@ -4605,7 +4649,7 @@ function build_events(registry, states, lanes, owners) {
4605
4649
  if (reader) readers.set(event_name, reader);
4606
4650
  }
4607
4651
  const snap2 = make_event_reader(event_tags(state2.state), "redact", null);
4608
- if (snap2) readers.set(_chunkH6KVPVP4cjs.SNAP_EVENT, snap2);
4652
+ if (snap2) readers.set(_chunkBCA423WPcjs.SNAP_EVENT, snap2);
4609
4653
  if (readers.size === 0) continue;
4610
4654
  state2.view = (event, actor) => (_nullishCoalesce(readers.get(event.name), () => ( IDENTITY_GATE)))(event, actor);
4611
4655
  }
@@ -4613,7 +4657,7 @@ function build_events(registry, states, lanes, owners) {
4613
4657
  return { sensitive: sensitive2, advisory, query_readers, handler_readers };
4614
4658
  }
4615
4659
  function reads_as_string(schema) {
4616
- const type = _optionalChain([_chunkH6KVPVP4cjs.def_of.call(void 0, _chunkH6KVPVP4cjs.output_of.call(void 0, schema)), 'optionalAccess', _168 => _168.type]);
4660
+ const type = _optionalChain([_chunkBCA423WPcjs.def_of.call(void 0, _chunkBCA423WPcjs.output_of.call(void 0, schema)), 'optionalAccess', _172 => _172.type]);
4617
4661
  return type === "string" || type === "transform";
4618
4662
  }
4619
4663
 
@@ -4671,7 +4715,7 @@ function act() {
4671
4715
  let _built = false;
4672
4716
  const read_wrap = (original) => {
4673
4717
  const wrapped = async (events, stream) => {
4674
- const read = events.map((e) => _nullishCoalesce(_optionalChain([_hr, 'access', _169 => _169.get, 'call', _170 => _170(e.name), 'optionalCall', _171 => _171(e)]), () => ( e)));
4718
+ const read = events.map((e) => _nullishCoalesce(_optionalChain([_hr, 'access', _173 => _173.get, 'call', _174 => _174(e.name), 'optionalCall', _175 => _175(e)]), () => ( e)));
4675
4719
  return original(read, stream);
4676
4720
  };
4677
4721
  const reset = original[FOLD_RESET];
@@ -4712,7 +4756,7 @@ function act() {
4712
4756
  });
4713
4757
  }
4714
4758
  for (const [action_name, handler] of Object.entries(state2.on)) {
4715
- const static_target = _optionalChain([handler, 'optionalAccess', _172 => _172._static_emit]);
4759
+ const static_target = _optionalChain([handler, 'optionalAccess', _176 => _176._static_emit]);
4716
4760
  if (static_target && deprecated.has(static_target)) {
4717
4761
  const current = current_version_of(static_target, event_names);
4718
4762
  throw new Error(
@@ -4725,7 +4769,7 @@ function act() {
4725
4769
  const list = deprecation_summary.map(
4726
4770
  (d) => `"${d.deprecated}" (current: "${d.current}", state: "${d.state_name}")`
4727
4771
  ).join(", ");
4728
- _chunkPRDX3HP6cjs.log.call(void 0, ).info(
4772
+ _chunk4UWU5FANcjs.log.call(void 0, ).info(
4729
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.`
4730
4774
  );
4731
4775
  }
@@ -4767,7 +4811,7 @@ function act() {
4767
4811
  return reaction_on(event, registry.events, builder);
4768
4812
  },
4769
4813
  build: (options) => {
4770
- _chunkPRDX3HP6cjs.resolveActConfig.call(void 0, options);
4814
+ _chunk4UWU5FANcjs.resolveActConfig.call(void 0, options);
4771
4815
  if (!_built) {
4772
4816
  for (const proj of pending_projections) add_projection(proj);
4773
4817
  for (const proj of fold_projections) {
@@ -4785,7 +4829,7 @@ function act() {
4785
4829
  `State projection "${proj.target}" of "${fold.name}" is missing events ${missing.join(", ")} \u2014 pass every partial of the state to .of()`
4786
4830
  );
4787
4831
  const claimed = fold_specs.find((s) => s.target === proj.target);
4788
- if (_optionalChain([claimed, 'optionalAccess', _173 => _173.projection]) === proj) continue;
4832
+ if (_optionalChain([claimed, 'optionalAccess', _177 => _177.projection]) === proj) continue;
4789
4833
  if (batch_handlers.has(proj.target) || claimed)
4790
4834
  throw new Error(
4791
4835
  `Duplicate projection target "${proj.target}" \u2014 a target is served by one batch handler or one state projection, never both`
@@ -4807,7 +4851,7 @@ function act() {
4807
4851
  for (const [name, gate] of built.query_readers) _qg.set(name, gate);
4808
4852
  for (const [name, gate] of built.handler_readers) _hr.set(name, gate);
4809
4853
  finalize_deprecations();
4810
- if (built.advisory) _chunkPRDX3HP6cjs.log.call(void 0, ).warn(built.advisory);
4854
+ if (built.advisory) _chunk4UWU5FANcjs.log.call(void 0, ).warn(built.advisory);
4811
4855
  for (const state2 of states.values()) {
4812
4856
  if (state2.disclose) _dp.set(state2.name, state2.disclose);
4813
4857
  if (state2.autoclose) _ac.set(state2.name, state2.autoclose);
@@ -4819,7 +4863,7 @@ function act() {
4819
4863
  synthesize_autoclose_reactions(
4820
4864
  registry,
4821
4865
  states,
4822
- _chunkPRDX3HP6cjs.current_autoclose_window
4866
+ _chunk4UWU5FANcjs.current_autoclose_window
4823
4867
  );
4824
4868
  Object.freeze(registry.actions);
4825
4869
  Object.freeze(registry.events);
@@ -4867,8 +4911,8 @@ function _projection(target) {
4867
4911
  handler,
4868
4912
  resolver: _nullishCoalesce(default_resolver, () => ( _this_)),
4869
4913
  options: {
4870
- blockOnError: _chunkPRDX3HP6cjs.DEFAULT_BLOCK_ON_ERROR,
4871
- maxRetries: _chunkPRDX3HP6cjs.DEFAULT_MAX_RETRIES
4914
+ blockOnError: _chunk4UWU5FANcjs.DEFAULT_BLOCK_ON_ERROR,
4915
+ maxRetries: _chunk4UWU5FANcjs.DEFAULT_MAX_RETRIES
4872
4916
  }
4873
4917
  }),
4874
4918
  widened
@@ -4909,7 +4953,7 @@ function _projection(target) {
4909
4953
  throw new Error(
4910
4954
  `Projection "${target}" .of() partials must share one state name \u2014 got "${name}" and "${partial.name}"`
4911
4955
  );
4912
- const config2 = _chunkPRDX3HP6cjs.resolveFoldConfig.call(void 0, options);
4956
+ const config2 = _chunk4UWU5FANcjs.resolveFoldConfig.call(void 0, options);
4913
4957
  const fold_events = {};
4914
4958
  for (const partial of partials)
4915
4959
  for (const [event_name, schema] of Object.entries(partial.events)) {
@@ -4927,8 +4971,8 @@ function _projection(target) {
4927
4971
  handler: noop,
4928
4972
  resolver: { target },
4929
4973
  options: {
4930
- blockOnError: _chunkPRDX3HP6cjs.DEFAULT_BLOCK_ON_ERROR,
4931
- maxRetries: _chunkPRDX3HP6cjs.DEFAULT_MAX_RETRIES
4974
+ blockOnError: _chunk4UWU5FANcjs.DEFAULT_BLOCK_ON_ERROR,
4975
+ maxRetries: _chunk4UWU5FANcjs.DEFAULT_MAX_RETRIES
4932
4976
  }
4933
4977
  }
4934
4978
  ]
@@ -5044,7 +5088,7 @@ function action_builder(state2) {
5044
5088
  throw new Error(`Duplicate action "${action2}"`);
5045
5089
  internal.actions[action2] = schema;
5046
5090
  if (options) {
5047
- _chunkPRDX3HP6cjs.resolveActionConfig.call(void 0, options);
5091
+ _chunk4UWU5FANcjs.resolveActionConfig.call(void 0, options);
5048
5092
  internal.options ??= {};
5049
5093
  internal.options[action2] = options;
5050
5094
  }
@@ -5338,5 +5382,7 @@ function write_line(writer, line) {
5338
5382
 
5339
5383
 
5340
5384
 
5341
- exports.Act = Act; exports.ActorSchema = _chunkH6KVPVP4cjs.ActorSchema; exports.CausationEventSchema = _chunkH6KVPVP4cjs.CausationEventSchema; exports.CommittedMetaSchema = _chunkH6KVPVP4cjs.CommittedMetaSchema; exports.ConcurrencyError = _chunkH6KVPVP4cjs.ConcurrencyError; exports.ConsoleLogger = _chunkPRDX3HP6cjs.ConsoleLogger; exports.CsvFile = CsvFile; exports.DEFAULT_LANE = _chunkH6KVPVP4cjs.DEFAULT_LANE; exports.DEFAULT_MAX_SUBSCRIBED_STREAMS = _chunkH6KVPVP4cjs.DEFAULT_MAX_SUBSCRIBED_STREAMS; exports.DEFAULT_SETTLE_DEBOUNCE_MS = _chunkH6KVPVP4cjs.DEFAULT_SETTLE_DEBOUNCE_MS; exports.DeferSignal = _chunkH6KVPVP4cjs.DeferSignal; exports.Environments = _chunkH6KVPVP4cjs.Environments; exports.Errors = _chunkH6KVPVP4cjs.Errors; exports.EventMetaSchema = _chunkH6KVPVP4cjs.EventMetaSchema; exports.ExitCodes = _chunkH6KVPVP4cjs.ExitCodes; exports.InMemoryCache = _chunkPRDX3HP6cjs.InMemoryCache; exports.InMemoryStore = _chunkPRDX3HP6cjs.InMemoryStore; exports.InvariantError = _chunkH6KVPVP4cjs.InvariantError; exports.LogLevels = _chunkH6KVPVP4cjs.LogLevels; exports.NonRetryableError = _chunkH6KVPVP4cjs.NonRetryableError; exports.PackageSchema = _chunkPRDX3HP6cjs.PackageSchema; exports.PreconditionError = _chunkH6KVPVP4cjs.PreconditionError; exports.QuerySchema = _chunkH6KVPVP4cjs.QuerySchema; exports.REDACTED = _chunkH6KVPVP4cjs.REDACTED; exports.SHREDDED = _chunkH6KVPVP4cjs.SHREDDED; exports.SNAP_EVENT = _chunkH6KVPVP4cjs.SNAP_EVENT; exports.StoreError = _chunkH6KVPVP4cjs.StoreError; exports.StreamClosedError = _chunkH6KVPVP4cjs.StreamClosedError; exports.TOMBSTONE_EVENT = _chunkH6KVPVP4cjs.TOMBSTONE_EVENT; exports.TargetSchema = _chunkH6KVPVP4cjs.TargetSchema; exports.ValidationError = _chunkH6KVPVP4cjs.ValidationError; exports.ZodEmpty = _chunkH6KVPVP4cjs.ZodEmpty; exports.act = act; exports.cache = _chunkPRDX3HP6cjs.cache; exports.config = _chunkPRDX3HP6cjs.config; exports.dateReviver = _chunkPRDX3HP6cjs.dateReviver; exports.default_scope = _chunkPRDX3HP6cjs.default_scope; exports.dispose = _chunkPRDX3HP6cjs.dispose; exports.disposeAndExit = _chunkPRDX3HP6cjs.disposeAndExit; exports.extend = _chunkPRDX3HP6cjs.extend; exports.is_literal_source = _chunkPRDX3HP6cjs.is_literal_source; exports.log = _chunkPRDX3HP6cjs.log; exports.pii_fields = _chunkH6KVPVP4cjs.pii_fields; exports.port = _chunkPRDX3HP6cjs.port; exports.projection = projection; exports.resolveAutocloseConfig = _chunkPRDX3HP6cjs.resolveAutocloseConfig2; exports.sensitive = _chunkH6KVPVP4cjs.sensitive; exports.sleep = _chunkPRDX3HP6cjs.sleep; exports.slice = slice; exports.state = state; exports.store = _chunkPRDX3HP6cjs.store; exports.validate = _chunkPRDX3HP6cjs.validate;
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;
5342
5388
  //# sourceMappingURL=index.cjs.map