@rotorsoft/act 1.37.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -3
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +5 -4
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts +2 -2
- package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
- package/dist/@types/builders/act-builder.d.ts.map +1 -1
- package/dist/@types/builders/merge.d.ts.map +1 -1
- package/dist/@types/builders/state-builder.d.ts +1 -1
- package/dist/@types/internal/autoclose-reaction.d.ts +8 -0
- package/dist/@types/internal/autoclose-reaction.d.ts.map +1 -1
- package/dist/@types/internal/classify.d.ts.map +1 -1
- package/dist/@types/internal/close-cycle.d.ts.map +1 -1
- package/dist/@types/internal/config.d.ts +11 -0
- package/dist/@types/internal/config.d.ts.map +1 -1
- package/dist/@types/internal/date-reviver.d.ts +6 -3
- package/dist/@types/internal/date-reviver.d.ts.map +1 -1
- package/dist/@types/internal/drain-ops.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts +6 -2
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/reaction-dispatch.d.ts +6 -0
- package/dist/@types/internal/reaction-dispatch.d.ts.map +1 -1
- package/dist/@types/internal/tracing.d.ts.map +1 -1
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/types/act.d.ts +0 -9
- package/dist/@types/types/act.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +36 -32
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/builders.d.ts +126 -47
- package/dist/@types/types/builders.d.ts.map +1 -1
- package/dist/@types/types/errors.d.ts +11 -43
- package/dist/@types/types/errors.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +51 -34
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +3 -3
- package/dist/@types/utils.d.ts +37 -12
- package/dist/@types/utils.d.ts.map +1 -1
- package/dist/{chunk-PRDX3HP6.cjs → chunk-LUHPSF3C.cjs} +73 -50
- package/dist/chunk-LUHPSF3C.cjs.map +1 -0
- package/dist/{chunk-HXW3TPP6.js → chunk-MWHTNPUY.js} +62 -39
- package/dist/chunk-MWHTNPUY.js.map +1 -0
- package/dist/{chunk-V5ZB54DC.js → chunk-SNPEQW6Z.js} +7 -21
- package/dist/chunk-SNPEQW6Z.js.map +1 -0
- package/dist/{chunk-H6KVPVP4.cjs → chunk-YFFWCVXW.cjs} +8 -22
- package/dist/chunk-YFFWCVXW.cjs.map +1 -0
- package/dist/index.cjs +1828 -1621
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1511 -1304
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +4 -4
- package/dist/test/index.js +2 -2
- package/dist/types/index.cjs +2 -4
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js +1 -3
- package/package.json +2 -2
- package/dist/chunk-H6KVPVP4.cjs.map +0 -1
- package/dist/chunk-HXW3TPP6.js.map +0 -1
- package/dist/chunk-PRDX3HP6.cjs.map +0 -1
- package/dist/chunk-V5ZB54DC.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
var _chunkPRDX3HP6cjs = require('./chunk-PRDX3HP6.cjs');
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
|
|
47
|
+
var _chunkLUHPSF3Ccjs = require('./chunk-LUHPSF3C.cjs');
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
|
|
@@ -74,24 +74,27 @@ var _chunkPRDX3HP6cjs = require('./chunk-PRDX3HP6.cjs');
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
var _chunkYFFWCVXWcjs = require('./chunk-YFFWCVXW.cjs');
|
|
78
81
|
|
|
79
82
|
// src/signals.ts
|
|
80
83
|
process.once("SIGINT", async (arg) => {
|
|
81
|
-
|
|
82
|
-
await
|
|
84
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).info(arg, "SIGINT");
|
|
85
|
+
await _chunkLUHPSF3Ccjs.disposeAndExit.call(void 0, "EXIT");
|
|
83
86
|
});
|
|
84
87
|
process.once("SIGTERM", async (arg) => {
|
|
85
|
-
|
|
86
|
-
await
|
|
88
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).info(arg, "SIGTERM");
|
|
89
|
+
await _chunkLUHPSF3Ccjs.disposeAndExit.call(void 0, "EXIT");
|
|
87
90
|
});
|
|
88
91
|
process.once("uncaughtException", async (arg) => {
|
|
89
|
-
|
|
90
|
-
await
|
|
92
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).error(arg, "Uncaught Exception");
|
|
93
|
+
await _chunkLUHPSF3Ccjs.disposeAndExit.call(void 0, "ERROR");
|
|
91
94
|
});
|
|
92
95
|
process.once("unhandledRejection", async (arg) => {
|
|
93
|
-
|
|
94
|
-
await
|
|
96
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).error(arg, "Unhandled Rejection");
|
|
97
|
+
await _chunkLUHPSF3Ccjs.disposeAndExit.call(void 0, "ERROR");
|
|
95
98
|
});
|
|
96
99
|
|
|
97
100
|
// src/act.ts
|
|
@@ -199,7 +202,7 @@ async function* audit(deps, categories, options = {}) {
|
|
|
199
202
|
if (need_stats) {
|
|
200
203
|
const stats = await deps.store().query_stats(
|
|
201
204
|
{},
|
|
202
|
-
{ count: true, names: true, exclude: [
|
|
205
|
+
{ count: true, names: true, exclude: [_chunkYFFWCVXWcjs.SNAP_EVENT] }
|
|
203
206
|
);
|
|
204
207
|
for (const [stream, s] of stats) {
|
|
205
208
|
for (const p of passes) _optionalChain([p, 'access', _4 => _4.on_stat, 'optionalCall', _5 => _5(stream, s)]);
|
|
@@ -281,7 +284,7 @@ var make_schema_pass = (deps) => {
|
|
|
281
284
|
return;
|
|
282
285
|
}
|
|
283
286
|
const schema = state2.events[name];
|
|
284
|
-
const sensitive2 =
|
|
287
|
+
const sensitive2 = _chunkYFFWCVXWcjs.pii_fields.call(void 0, schema);
|
|
285
288
|
let parse_schema = schema;
|
|
286
289
|
if (sensitive2.length > 0) {
|
|
287
290
|
const omitter = schema.omit;
|
|
@@ -415,7 +418,7 @@ var make_restart_candidate_pass = (deps, options) => {
|
|
|
415
418
|
{
|
|
416
419
|
stream,
|
|
417
420
|
stream_exact: true,
|
|
418
|
-
names: [
|
|
421
|
+
names: [_chunkYFFWCVXWcjs.SNAP_EVENT],
|
|
419
422
|
with_snaps: true,
|
|
420
423
|
// From the start: on its own, `with_snaps` resumes at the latest.
|
|
421
424
|
after: -1
|
|
@@ -575,7 +578,7 @@ var make_correlation_gaps_pass = () => {
|
|
|
575
578
|
seen_ids.add(e.id);
|
|
576
579
|
const causation = _optionalChain([e, 'access', _31 => _31.meta, 'optionalAccess', _32 => _32.causation]);
|
|
577
580
|
const parent_id = _optionalChain([causation, 'optionalAccess', _33 => _33.event, 'optionalAccess', _34 => _34.id]);
|
|
578
|
-
if (parent_id !== void 0 && e.name !==
|
|
581
|
+
if (parent_id !== void 0 && e.name !== _chunkYFFWCVXWcjs.TOMBSTONE_EVENT) {
|
|
579
582
|
checks.push({ stream: e.stream, id: e.id, parent_id });
|
|
580
583
|
}
|
|
581
584
|
},
|
|
@@ -750,6 +753,7 @@ var CircuitBreaker = (_class = class {
|
|
|
750
753
|
|
|
751
754
|
// src/internal/classify.ts
|
|
752
755
|
var ALL_LANES = /* @__PURE__ */ Symbol("act/all-lanes");
|
|
756
|
+
var describe_source = (source) => source === void 0 ? "no source (every stream)" : `"${source}"`;
|
|
753
757
|
function classify_registry(registry, states) {
|
|
754
758
|
const statics = /* @__PURE__ */ new Map();
|
|
755
759
|
const target_lanes = /* @__PURE__ */ new Map();
|
|
@@ -776,6 +780,10 @@ function classify_registry(registry, states) {
|
|
|
776
780
|
);
|
|
777
781
|
}
|
|
778
782
|
const existing = statics.get(target);
|
|
783
|
+
if (existing && existing.source !== source)
|
|
784
|
+
throw new Error(
|
|
785
|
+
`Target "${target}" has reactions on two sources, ${describe_source(existing.source)} and ${describe_source(source)}. A target reads one source, so the second would miss events or read too many. Give it its own target.`
|
|
786
|
+
);
|
|
779
787
|
if (!existing) {
|
|
780
788
|
statics.set(target, { stream: target, source, priority, lane });
|
|
781
789
|
} else if (priority > existing.priority) {
|
|
@@ -797,674 +805,303 @@ function classify_registry(registry, states) {
|
|
|
797
805
|
};
|
|
798
806
|
}
|
|
799
807
|
|
|
800
|
-
// src/internal/
|
|
801
|
-
var
|
|
802
|
-
var
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
await correlate(CLOSE_CATCH_UP_LIMIT);
|
|
808
|
-
if (cursor.checkpoint <= before) break;
|
|
809
|
-
}
|
|
810
|
-
return cursor.checkpoint;
|
|
808
|
+
// src/internal/autoclose-policy.ts
|
|
809
|
+
var _zod = require('zod');
|
|
810
|
+
var DAY_MS = 864e5;
|
|
811
|
+
var MIN_AFTER_DAYS = 1 / 1440;
|
|
812
|
+
var MIN_KEEP_DAYS = 1;
|
|
813
|
+
function days_after(date, days) {
|
|
814
|
+
return new Date(date.getTime() + days * DAY_MS);
|
|
811
815
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
816
|
+
function days_before_now(days) {
|
|
817
|
+
return new Date(Date.now() - days * DAY_MS);
|
|
818
|
+
}
|
|
819
|
+
var window_schema = (field, min_days, floor) => _zod.z.object({
|
|
820
|
+
days: _zod.z.number({ message: `autocloses: ${field}.days must be a number` }).positive(`autocloses: ${field}.days must be > 0`)
|
|
821
|
+
}).refine((o) => o.days >= min_days, {
|
|
822
|
+
message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`
|
|
823
|
+
});
|
|
824
|
+
var AfterSchema = window_schema("after", MIN_AFTER_DAYS, "one minute");
|
|
825
|
+
var KeepSchema = window_schema("keep", MIN_KEEP_DAYS, "one day");
|
|
826
|
+
var IsSchema = _zod.z.union([
|
|
827
|
+
_zod.z.string().min(1, "autocloses: is must be a non-empty event name"),
|
|
828
|
+
_zod.z.array(
|
|
829
|
+
_zod.z.string().min(1, "autocloses: is entries must be non-empty event names")
|
|
830
|
+
).min(1, "autocloses: is must include at least one event name").readonly()
|
|
831
|
+
]);
|
|
832
|
+
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");
|
|
833
|
+
var OrBlockSchema = _zod.z.object({
|
|
834
|
+
after: AfterSchema.optional(),
|
|
835
|
+
is: IsSchema.optional(),
|
|
836
|
+
reaches: ReachesSchema.optional()
|
|
837
|
+
}).strict().refine(
|
|
838
|
+
(o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0,
|
|
839
|
+
{
|
|
840
|
+
message: "autocloses: `or` block must include at least one of after / is / reaches"
|
|
824
841
|
}
|
|
825
|
-
|
|
826
|
-
var
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
842
|
+
);
|
|
843
|
+
var AutoclosePolicySchema = _zod.z.object({
|
|
844
|
+
after: AfterSchema.optional(),
|
|
845
|
+
is: IsSchema.optional(),
|
|
846
|
+
reaches: ReachesSchema.optional(),
|
|
847
|
+
or: OrBlockSchema.optional(),
|
|
848
|
+
keep: KeepSchema.optional()
|
|
849
|
+
}).strict().refine(
|
|
850
|
+
(o) => o.after !== void 0 || o.is !== void 0 || o.reaches !== void 0 || o.or !== void 0 || o.keep !== void 0,
|
|
851
|
+
{
|
|
852
|
+
message: "autocloses: at least one of after / is / reaches / or / keep must be specified \u2014 empty `{}` is a misconfiguration"
|
|
834
853
|
}
|
|
835
|
-
|
|
836
|
-
|
|
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 };
|
|
854
|
+
);
|
|
855
|
+
function compile_after(after) {
|
|
856
|
+
return (_stream, head) => days_after(head.created, after.days) <= /* @__PURE__ */ new Date();
|
|
851
857
|
}
|
|
852
|
-
function
|
|
853
|
-
const
|
|
854
|
-
return
|
|
855
|
-
(inner, stream) => () => with_lock(stream, inner),
|
|
856
|
-
work
|
|
857
|
-
)();
|
|
858
|
+
function compile_is(is) {
|
|
859
|
+
const set = new Set(typeof is === "string" ? [is] : is);
|
|
860
|
+
return (_stream, head) => set.has(head.name);
|
|
858
861
|
}
|
|
859
|
-
|
|
860
|
-
|
|
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
|
-
);
|
|
862
|
+
function compile_reaches(reaches) {
|
|
863
|
+
return (_stream, _head, count) => count >= reaches;
|
|
913
864
|
}
|
|
914
|
-
|
|
915
|
-
const
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
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;
|
|
865
|
+
function policy_min_after_days(options) {
|
|
866
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
867
|
+
const windows = [];
|
|
868
|
+
if (parsed.after) windows.push(parsed.after.days);
|
|
869
|
+
if (_optionalChain([parsed, 'access', _42 => _42.or, 'optionalAccess', _43 => _43.after])) windows.push(parsed.or.after.days);
|
|
870
|
+
return windows.length ? Math.min(...windows) : void 0;
|
|
938
871
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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;
|
|
872
|
+
function policy_after_windows(options) {
|
|
873
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
874
|
+
return [parsed.after, _optionalChain([parsed, 'access', _44 => _44.or, 'optionalAccess', _45 => _45.after])].flatMap((w) => w ? [w.days] : []);
|
|
951
875
|
}
|
|
952
|
-
|
|
953
|
-
const
|
|
954
|
-
|
|
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;
|
|
876
|
+
function policy_keep_days(options) {
|
|
877
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
878
|
+
return _optionalChain([parsed, 'access', _46 => _46.keep, 'optionalAccess', _47 => _47.days]);
|
|
970
879
|
}
|
|
971
|
-
function
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
880
|
+
function compile_autoclose_policy(options) {
|
|
881
|
+
const parsed = AutoclosePolicySchema.parse(options);
|
|
882
|
+
const and_preds = [];
|
|
883
|
+
if (parsed.after) and_preds.push(compile_after(parsed.after));
|
|
884
|
+
if (parsed.is) and_preds.push(compile_is(parsed.is));
|
|
885
|
+
if (parsed.reaches) and_preds.push(compile_reaches(parsed.reaches));
|
|
886
|
+
const or_preds = [];
|
|
887
|
+
if (parsed.or) {
|
|
888
|
+
if (parsed.or.after) or_preds.push(compile_after(parsed.or.after));
|
|
889
|
+
if (parsed.or.is) or_preds.push(compile_is(parsed.or.is));
|
|
890
|
+
if (parsed.or.reaches) or_preds.push(compile_reaches(parsed.or.reaches));
|
|
891
|
+
}
|
|
892
|
+
return (stream, head, count) => {
|
|
893
|
+
if (and_preds.length > 0 && and_preds.every((p) => p(stream, head, count))) {
|
|
894
|
+
return true;
|
|
979
895
|
}
|
|
980
|
-
|
|
896
|
+
if (or_preds.some((p) => p(stream, head, count))) {
|
|
897
|
+
return true;
|
|
898
|
+
}
|
|
899
|
+
return false;
|
|
981
900
|
};
|
|
982
901
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
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;
|
|
902
|
+
|
|
903
|
+
// src/internal/autoclose-window.ts
|
|
904
|
+
function hour_in_zone(now, timeZone) {
|
|
905
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
906
|
+
timeZone,
|
|
907
|
+
hour: "2-digit",
|
|
908
|
+
hourCycle: "h23"
|
|
909
|
+
}).formatToParts(now);
|
|
910
|
+
return Number(_optionalChain([parts, 'access', _48 => _48.find, 'call', _49 => _49((p) => p.type === "hour"), 'optionalAccess', _50 => _50.value]));
|
|
1003
911
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
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;
|
|
912
|
+
function hour_in_range(hour, start, end) {
|
|
913
|
+
return start < end ? hour >= start && hour < end : hour >= start || hour < end;
|
|
1036
914
|
}
|
|
1037
|
-
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
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 };
|
|
915
|
+
function is_dst_gap_open(now, timeZone, start) {
|
|
916
|
+
const hour = hour_in_zone(now, timeZone);
|
|
917
|
+
if (hour <= start) return false;
|
|
918
|
+
const prev = hour_in_zone(new Date(now.getTime() - 36e5), timeZone);
|
|
919
|
+
return prev === start - 1 && hour === start + 1;
|
|
1058
920
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
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;
|
|
921
|
+
function in_autoclose_window(window, now) {
|
|
922
|
+
if (!window) return true;
|
|
923
|
+
const hour = hour_in_zone(now, window.timeZone);
|
|
924
|
+
return hour_in_range(hour, window.start, window.end) || is_dst_gap_open(now, window.timeZone, window.start);
|
|
1076
925
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
926
|
+
function next_window_open(window, now) {
|
|
927
|
+
const start_ms = now.getTime();
|
|
928
|
+
for (let h = 0; h <= 48; h++) {
|
|
929
|
+
const candidate = new Date(start_ms + h * 36e5);
|
|
930
|
+
if (hour_in_zone(candidate, window.timeZone) === window.start)
|
|
931
|
+
return candidate;
|
|
932
|
+
const boundary = new Date(
|
|
933
|
+
candidate.getTime() - candidate.getTime() % 36e5
|
|
934
|
+
);
|
|
935
|
+
if (boundary.getTime() >= start_ms && is_dst_gap_open(boundary, window.timeZone, window.start))
|
|
936
|
+
return boundary;
|
|
1081
937
|
}
|
|
938
|
+
return new Date(start_ms + 864e5);
|
|
1082
939
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
940
|
+
|
|
941
|
+
// src/internal/defer-config.ts
|
|
942
|
+
|
|
943
|
+
var DeferDurationSchema = _zod.z.object({
|
|
944
|
+
days: _zod.z.number().positive().optional(),
|
|
945
|
+
hours: _zod.z.number().positive().optional(),
|
|
946
|
+
minutes: _zod.z.number().positive().optional()
|
|
947
|
+
}).strict().refine((d) => d.days != null || d.hours != null || d.minutes != null, {
|
|
948
|
+
message: "defer: a duration needs at least one of days, hours, or minutes"
|
|
949
|
+
});
|
|
950
|
+
var DeferWhenSchema = _zod.z.object({
|
|
951
|
+
after: DeferDurationSchema.optional(),
|
|
952
|
+
at: _zod.z.date().optional()
|
|
953
|
+
}).strict().refine((w) => w.after === void 0 !== (w.at === void 0), {
|
|
954
|
+
message: "defer: specify exactly one of `after` or `at`"
|
|
955
|
+
});
|
|
956
|
+
function duration_ms(d) {
|
|
957
|
+
return (_nullishCoalesce(d.days, () => ( 0))) * 864e5 + (_nullishCoalesce(d.hours, () => ( 0))) * 36e5 + (_nullishCoalesce(d.minutes, () => ( 0))) * 6e4;
|
|
1091
958
|
}
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
|
|
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;
|
|
959
|
+
function resolve_defer_at(when, event) {
|
|
960
|
+
const parsed = DeferWhenSchema.parse(when);
|
|
961
|
+
if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);
|
|
962
|
+
return parsed.at.getTime();
|
|
963
|
+
}
|
|
964
|
+
function assert_defer_when(when) {
|
|
965
|
+
DeferWhenSchema.parse(when);
|
|
966
|
+
}
|
|
967
|
+
function make_deferred(handler, schedule) {
|
|
968
|
+
const call = handler;
|
|
969
|
+
const deferred = async (event, stream, app) => {
|
|
970
|
+
const when = typeof schedule === "function" ? schedule(event) : schedule;
|
|
971
|
+
if (Date.now() < resolve_defer_at(when, event)) throw new (0, _chunkYFFWCVXWcjs.DeferSignal)(when);
|
|
972
|
+
return call(event, stream, app);
|
|
973
|
+
};
|
|
974
|
+
Object.defineProperty(deferred, "name", { value: handler.name });
|
|
975
|
+
return deferred;
|
|
1127
976
|
}
|
|
1128
977
|
|
|
1129
|
-
// src/internal/
|
|
978
|
+
// src/internal/drain-cycle.ts
|
|
1130
979
|
var _crypto = require('crypto');
|
|
1131
980
|
|
|
1132
|
-
// src/internal/
|
|
1133
|
-
function
|
|
1134
|
-
if (
|
|
1135
|
-
|
|
1136
|
-
|
|
981
|
+
// src/internal/backoff.ts
|
|
982
|
+
function compute_backoff_delay(retry, opts) {
|
|
983
|
+
if (!opts || opts.baseMs <= 0) return 0;
|
|
984
|
+
const r = Math.max(0, retry);
|
|
985
|
+
let delay;
|
|
986
|
+
switch (opts.strategy) {
|
|
987
|
+
case "fixed":
|
|
988
|
+
delay = opts.baseMs;
|
|
989
|
+
break;
|
|
990
|
+
case "linear":
|
|
991
|
+
delay = opts.baseMs * (r + 1);
|
|
992
|
+
break;
|
|
993
|
+
case "exponential":
|
|
994
|
+
delay = opts.baseMs * 2 ** r;
|
|
995
|
+
if (opts.maxMs !== void 0) delay = Math.min(delay, opts.maxMs);
|
|
996
|
+
break;
|
|
997
|
+
default: {
|
|
998
|
+
const _never = opts.strategy;
|
|
999
|
+
throw new Error(`unknown backoff strategy: ${String(_never)}`);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (opts.jitter) delay = delay * (0.5 + Math.random());
|
|
1003
|
+
return Math.max(0, Math.floor(delay));
|
|
1137
1004
|
}
|
|
1138
1005
|
|
|
1139
|
-
// src/internal/
|
|
1140
|
-
var
|
|
1141
|
-
var
|
|
1142
|
-
|
|
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
|
-
|
|
1006
|
+
// src/internal/defer-timer.ts
|
|
1007
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1008
|
+
var DeferTimer = (_class2 = class {
|
|
1009
|
+
__init2() {this._due = /* @__PURE__ */ new Map()}
|
|
1187
1010
|
|
|
1188
1011
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
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;
|
|
1012
|
+
/**
|
|
1013
|
+
* @param on_wake - invoked once each time the earliest due-time elapses.
|
|
1014
|
+
* The consumer re-schedules for whatever is still parked.
|
|
1015
|
+
*/
|
|
1016
|
+
constructor(on_wake) {;_class2.prototype.__init2.call(this);
|
|
1017
|
+
this._on_wake = on_wake;
|
|
1210
1018
|
}
|
|
1211
|
-
/**
|
|
1212
|
-
|
|
1213
|
-
this.
|
|
1019
|
+
/** Number of currently parked streams. */
|
|
1020
|
+
get size() {
|
|
1021
|
+
return this._due.size;
|
|
1214
1022
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1023
|
+
/**
|
|
1024
|
+
* Park `stream` for a re-visit at `at` (ms since epoch). A plain
|
|
1025
|
+
* overwrite: the caller computes the authoritative next-visit for the
|
|
1026
|
+
* stream (the drain's `handle` already reconciles a stream's reactions
|
|
1027
|
+
* into one result per cycle), so there is no stale value to merge against.
|
|
1028
|
+
*/
|
|
1029
|
+
set(stream, at) {
|
|
1030
|
+
this._due.set(stream, at);
|
|
1221
1031
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
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()]);
|
|
1032
|
+
/** Drop `stream` from the parked set (e.g. on a successful ack or block). */
|
|
1033
|
+
delete(stream) {
|
|
1034
|
+
this._due.delete(stream);
|
|
1234
1035
|
}
|
|
1235
1036
|
/**
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1037
|
+
* Drop every entry due at or before `before`. The drain calls it when a
|
|
1038
|
+
* pass that started at `before` claimed nothing: whatever was due by then
|
|
1039
|
+
* was handled elsewhere (another worker) or has no work left, so waking
|
|
1040
|
+
* for it again would spin.
|
|
1238
1041
|
*/
|
|
1239
|
-
|
|
1240
|
-
this.
|
|
1241
|
-
|
|
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);
|
|
1042
|
+
prune(before) {
|
|
1043
|
+
for (const [stream, at] of this._due)
|
|
1044
|
+
if (at <= before) this._due.delete(stream);
|
|
1255
1045
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1046
|
+
/**
|
|
1047
|
+
* (Re)schedule the wake timer at the earliest pending due-time. Idempotent
|
|
1048
|
+
* — collapses many parked streams into a single timer. A no-op clears any
|
|
1049
|
+
* pending timer when the map is empty.
|
|
1050
|
+
*
|
|
1051
|
+
* The timer is `unref()`-ed so pending re-visits never keep the process
|
|
1052
|
+
* alive on their own.
|
|
1053
|
+
*/
|
|
1054
|
+
schedule() {
|
|
1055
|
+
if (this._timer) clearTimeout(this._timer);
|
|
1056
|
+
if (this._due.size === 0) {
|
|
1057
|
+
this._timer = void 0;
|
|
1058
|
+
return;
|
|
1264
1059
|
}
|
|
1265
|
-
|
|
1060
|
+
let earliest = Number.POSITIVE_INFINITY;
|
|
1061
|
+
for (const t of this._due.values()) if (t < earliest) earliest = t;
|
|
1062
|
+
const delay = Math.min(
|
|
1063
|
+
Math.max(0, earliest - Date.now()),
|
|
1064
|
+
MAX_TIMER_DELAY_MS
|
|
1065
|
+
);
|
|
1066
|
+
this._timer = setTimeout(() => {
|
|
1067
|
+
this._timer = void 0;
|
|
1068
|
+
this._on_wake();
|
|
1069
|
+
}, delay);
|
|
1070
|
+
this._timer.unref();
|
|
1266
1071
|
}
|
|
1267
|
-
/**
|
|
1268
|
-
|
|
1269
|
-
if (this.
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
try {
|
|
1273
|
-
return await pass;
|
|
1274
|
-
} finally {
|
|
1275
|
-
this._passes.delete(pass);
|
|
1072
|
+
/** Cancel any pending wake timer. Idempotent. Leaves the parked set intact. */
|
|
1073
|
+
stop() {
|
|
1074
|
+
if (this._timer) {
|
|
1075
|
+
clearTimeout(this._timer);
|
|
1076
|
+
this._timer = void 0;
|
|
1276
1077
|
}
|
|
1277
1078
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
if (lease
|
|
1289
|
-
|
|
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();
|
|
1297
|
-
}
|
|
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 }
|
|
1374
|
-
);
|
|
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 };
|
|
1410
|
-
}
|
|
1411
|
-
this._checkpoint = last_id;
|
|
1412
|
-
if (!stopped && found !== limit) this._lowered = raised;
|
|
1413
|
-
return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
|
|
1079
|
+
}, _class2);
|
|
1080
|
+
|
|
1081
|
+
// src/internal/drain-ratio.ts
|
|
1082
|
+
var RATIO_MIN = 0.2;
|
|
1083
|
+
var RATIO_MAX = 0.8;
|
|
1084
|
+
var RATIO_DEFAULT = 0.5;
|
|
1085
|
+
function compute_lag_lead_ratio(handled, lagging, leading) {
|
|
1086
|
+
let lagging_handled = 0;
|
|
1087
|
+
let leading_handled = 0;
|
|
1088
|
+
for (const { lease, handled: count } of handled) {
|
|
1089
|
+
if (lease.lagging) lagging_handled += count;
|
|
1090
|
+
else leading_handled += count;
|
|
1414
1091
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
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
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
}, _class3);
|
|
1092
|
+
const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;
|
|
1093
|
+
const leading_avg = leading > 0 ? leading_handled / leading : 0;
|
|
1094
|
+
const total = lagging_avg + leading_avg;
|
|
1095
|
+
if (total === 0) return RATIO_DEFAULT;
|
|
1096
|
+
return Math.max(RATIO_MIN, Math.min(RATIO_MAX, lagging_avg / total));
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// src/internal/report-once.ts
|
|
1100
|
+
function report_once(seen, key, message) {
|
|
1101
|
+
if (seen.has(key)) return;
|
|
1102
|
+
seen.add(key);
|
|
1103
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).error(new Error(message));
|
|
1104
|
+
}
|
|
1468
1105
|
|
|
1469
1106
|
// src/internal/correlation-id.ts
|
|
1470
1107
|
|
|
@@ -1490,136 +1127,15 @@ function close_correlation(correlator, actor) {
|
|
|
1490
1127
|
});
|
|
1491
1128
|
}
|
|
1492
1129
|
|
|
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
1130
|
// src/internal/drain-ops.ts
|
|
1615
|
-
var claim = (lagging, leading, by, millis, lane) =>
|
|
1131
|
+
var claim = (lagging, leading, by, millis, lane) => _chunkLUHPSF3Ccjs.store.call(void 0, ).claim(lagging, leading, by, millis, lane);
|
|
1616
1132
|
async function fetch(leased, eventLimit) {
|
|
1617
1133
|
return Promise.all(
|
|
1618
1134
|
leased.map(async ({ stream, source, at, lagging }) => {
|
|
1619
1135
|
const events = [];
|
|
1620
|
-
const stream_exact = source !== void 0 &&
|
|
1136
|
+
const stream_exact = source !== void 0 && _chunkLUHPSF3Ccjs.is_literal_source.call(void 0, source, stream) ? true : void 0;
|
|
1621
1137
|
try {
|
|
1622
|
-
await
|
|
1138
|
+
await _chunkLUHPSF3Ccjs.store.call(void 0, ).query((e) => events.push(e), {
|
|
1623
1139
|
stream: source,
|
|
1624
1140
|
stream_exact,
|
|
1625
1141
|
after: at,
|
|
@@ -1632,23 +1148,23 @@ async function fetch(leased, eventLimit) {
|
|
|
1632
1148
|
at,
|
|
1633
1149
|
lagging,
|
|
1634
1150
|
events: [],
|
|
1635
|
-
error: _nullishCoalesce(_optionalChain([error, 'optionalAccess',
|
|
1151
|
+
error: _nullishCoalesce(_optionalChain([error, 'optionalAccess', _51 => _51.message]), () => ( String(error)))
|
|
1636
1152
|
};
|
|
1637
1153
|
}
|
|
1638
1154
|
return { stream, source, at, lagging, events };
|
|
1639
1155
|
})
|
|
1640
1156
|
);
|
|
1641
1157
|
}
|
|
1642
|
-
var ack = (leases) =>
|
|
1643
|
-
var block = (leases) =>
|
|
1644
|
-
var subscribe = (streams, correlated_at, correlator) =>
|
|
1158
|
+
var ack = (leases) => _chunkLUHPSF3Ccjs.store.call(void 0, ).ack(leases);
|
|
1159
|
+
var block = (leases) => _chunkLUHPSF3Ccjs.store.call(void 0, ).block(leases);
|
|
1160
|
+
var subscribe = (streams, correlated_at, correlator) => _chunkLUHPSF3Ccjs.store.call(void 0, ).subscribe(streams, correlated_at, correlator);
|
|
1645
1161
|
|
|
1646
1162
|
// src/internal/event-sourcing.ts
|
|
1647
1163
|
var _actpatch = require('@rotorsoft/act-patch');
|
|
1648
|
-
|
|
1164
|
+
|
|
1649
1165
|
var bare_patch = (_me, state2, partial) => _actpatch.patch.call(void 0, state2, partial);
|
|
1650
1166
|
var value_at = (value, path) => path.reduce(
|
|
1651
|
-
(at, key) => _optionalChain([at, 'optionalAccess',
|
|
1167
|
+
(at, key) => _optionalChain([at, 'optionalAccess', _52 => _52[key]]),
|
|
1652
1168
|
value
|
|
1653
1169
|
);
|
|
1654
1170
|
var check_invariants = (target, state2, schema, pii_aware) => {
|
|
@@ -1656,29 +1172,29 @@ var check_invariants = (target, state2, schema, pii_aware) => {
|
|
|
1656
1172
|
try {
|
|
1657
1173
|
result = schema.safeParse(state2);
|
|
1658
1174
|
} catch (error) {
|
|
1659
|
-
throw new (0,
|
|
1175
|
+
throw new (0, _chunkYFFWCVXWcjs.ValidationError)(target, state2, error);
|
|
1660
1176
|
}
|
|
1661
1177
|
if (result.success) return;
|
|
1662
1178
|
const issues = pii_aware ? result.error.issues.filter((issue) => {
|
|
1663
1179
|
const value = value_at(state2, issue.path);
|
|
1664
|
-
return value !==
|
|
1180
|
+
return value !== _chunkYFFWCVXWcjs.REDACTED && value !== _chunkYFFWCVXWcjs.SHREDDED;
|
|
1665
1181
|
}) : result.error.issues;
|
|
1666
1182
|
if (issues.length)
|
|
1667
|
-
throw new (0,
|
|
1183
|
+
throw new (0, _chunkYFFWCVXWcjs.ValidationError)(
|
|
1668
1184
|
target,
|
|
1669
1185
|
state2,
|
|
1670
1186
|
_zod.prettifyError.call(void 0, new (0, _zod.ZodError)(issues))
|
|
1671
1187
|
);
|
|
1672
1188
|
};
|
|
1673
1189
|
var DEFAULT_BATCH = 500;
|
|
1674
|
-
var cache_put = (stream, entry) =>
|
|
1675
|
-
(err) =>
|
|
1190
|
+
var cache_put = (stream, entry) => _chunkLUHPSF3Ccjs.cache.call(void 0, ).set(stream, entry).catch(
|
|
1191
|
+
(err) => _chunkLUHPSF3Ccjs.log.call(void 0, ).warn(
|
|
1676
1192
|
err,
|
|
1677
1193
|
"cache set skipped; the next load re-folds from the store"
|
|
1678
1194
|
)
|
|
1679
1195
|
);
|
|
1680
|
-
var cache_drop = (stream) =>
|
|
1681
|
-
(err) =>
|
|
1196
|
+
var cache_drop = (stream) => _chunkLUHPSF3Ccjs.cache.call(void 0, ).invalidate(stream).catch(
|
|
1197
|
+
(err) => _chunkLUHPSF3Ccjs.log.call(void 0, ).warn(
|
|
1682
1198
|
err,
|
|
1683
1199
|
"cache invalidate skipped; a stale checkpoint re-folds from its event_id"
|
|
1684
1200
|
)
|
|
@@ -1686,35 +1202,43 @@ var cache_drop = (stream) => _chunkPRDX3HP6cjs.cache.call(void 0, ).invalidate(s
|
|
|
1686
1202
|
async function snap(snapshot) {
|
|
1687
1203
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
1688
1204
|
try {
|
|
1689
|
-
const [committed] = await
|
|
1690
|
-
|
|
1691
|
-
|
|
1205
|
+
const [committed] = await _chunkLUHPSF3Ccjs.store.call(void 0, ).commit(
|
|
1206
|
+
[
|
|
1207
|
+
{
|
|
1208
|
+
stream,
|
|
1209
|
+
msgs: [{ name: _chunkYFFWCVXWcjs.SNAP_EVENT, data: snapshot.state }],
|
|
1210
|
+
// IMPORTANT! - state events are committed right after the snapshot event
|
|
1211
|
+
expectedVersion: version
|
|
1212
|
+
}
|
|
1213
|
+
],
|
|
1692
1214
|
{
|
|
1693
1215
|
correlation: meta.correlation,
|
|
1694
1216
|
causation: { event: { id, name, stream } }
|
|
1695
|
-
}
|
|
1696
|
-
version
|
|
1697
|
-
// IMPORTANT! - state events are committed right after the snapshot event
|
|
1217
|
+
}
|
|
1698
1218
|
);
|
|
1699
1219
|
return committed;
|
|
1700
1220
|
} catch (error) {
|
|
1701
1221
|
const reason = error instanceof Error ? error.message : String(error);
|
|
1702
|
-
|
|
1222
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).warn(
|
|
1703
1223
|
`Snapshot write failed on stream "${stream}": ${reason} \u2014 cold starts will replay full history until snapshots succeed.`
|
|
1704
1224
|
);
|
|
1705
1225
|
}
|
|
1706
1226
|
}
|
|
1707
1227
|
async function tombstone(stream, expectedVersion, correlation) {
|
|
1708
1228
|
try {
|
|
1709
|
-
const [committed] = await
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1229
|
+
const [committed] = await _chunkLUHPSF3Ccjs.store.call(void 0, ).commit(
|
|
1230
|
+
[
|
|
1231
|
+
{
|
|
1232
|
+
stream,
|
|
1233
|
+
msgs: [{ name: _chunkYFFWCVXWcjs.TOMBSTONE_EVENT, data: {} }],
|
|
1234
|
+
expectedVersion
|
|
1235
|
+
}
|
|
1236
|
+
],
|
|
1237
|
+
{ correlation, causation: {} }
|
|
1714
1238
|
);
|
|
1715
1239
|
return committed;
|
|
1716
1240
|
} catch (error) {
|
|
1717
|
-
if (error instanceof
|
|
1241
|
+
if (error instanceof _chunkYFFWCVXWcjs.ConcurrencyError) return void 0;
|
|
1718
1242
|
throw error;
|
|
1719
1243
|
}
|
|
1720
1244
|
}
|
|
@@ -1744,9 +1268,9 @@ async function scan(source, opts = {}, callback) {
|
|
|
1744
1268
|
if (drop_closed_streams) {
|
|
1745
1269
|
await source.query(
|
|
1746
1270
|
(e) => {
|
|
1747
|
-
if (e.name ===
|
|
1271
|
+
if (e.name === _chunkYFFWCVXWcjs.TOMBSTONE_EVENT) closed_streams.add(e.stream);
|
|
1748
1272
|
},
|
|
1749
|
-
{ names: [
|
|
1273
|
+
{ names: [_chunkYFFWCVXWcjs.TOMBSTONE_EVENT] }
|
|
1750
1274
|
);
|
|
1751
1275
|
}
|
|
1752
1276
|
let max_id;
|
|
@@ -1768,16 +1292,16 @@ async function scan(source, opts = {}, callback) {
|
|
|
1768
1292
|
if (!is_valid(event))
|
|
1769
1293
|
throw new Error(`Invalid event at index ${processed}`);
|
|
1770
1294
|
if (on_progress) on_progress({ processed, id: event.id, max_id });
|
|
1771
|
-
if (drop_snapshots && event.name ===
|
|
1295
|
+
if (drop_snapshots && event.name === _chunkYFFWCVXWcjs.SNAP_EVENT) {
|
|
1772
1296
|
dropped_snaps++;
|
|
1773
1297
|
return;
|
|
1774
1298
|
}
|
|
1775
|
-
if (closed_streams.has(event.stream) && event.name !==
|
|
1299
|
+
if (closed_streams.has(event.stream) && event.name !== _chunkYFFWCVXWcjs.TOMBSTONE_EVENT) {
|
|
1776
1300
|
dropped_closed++;
|
|
1777
1301
|
return;
|
|
1778
1302
|
}
|
|
1779
1303
|
let migrated = event;
|
|
1780
|
-
const migration = _optionalChain([event_migrations, 'optionalAccess',
|
|
1304
|
+
const migration = _optionalChain([event_migrations, 'optionalAccess', _53 => _53[event.name]]);
|
|
1781
1305
|
if (migration) {
|
|
1782
1306
|
const old_data = migration.from_schema.parse(event.data);
|
|
1783
1307
|
const new_data = migration.migrate(old_data);
|
|
@@ -1799,7 +1323,7 @@ async function scan(source, opts = {}, callback) {
|
|
|
1799
1323
|
return;
|
|
1800
1324
|
}
|
|
1801
1325
|
let remapped = migrated;
|
|
1802
|
-
const caused_by = _optionalChain([migrated, 'access',
|
|
1326
|
+
const caused_by = _optionalChain([migrated, 'access', _54 => _54.meta, 'access', _55 => _55.causation, 'access', _56 => _56.event, 'optionalAccess', _57 => _57.id]);
|
|
1803
1327
|
if (caused_by !== void 0) {
|
|
1804
1328
|
const new_caused_by = id_map.get(caused_by);
|
|
1805
1329
|
if (new_caused_by !== void 0 && new_caused_by !== caused_by) {
|
|
@@ -1840,18 +1364,18 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1840
1364
|
const { stream, actor, asOf } = target;
|
|
1841
1365
|
const time_travel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
|
|
1842
1366
|
const seeded = time_travel && asOf.limit === void 0 && !asOf.created_after;
|
|
1843
|
-
const cached = time_travel ? void 0 : await
|
|
1367
|
+
const cached = time_travel ? void 0 : await _chunkLUHPSF3Ccjs.cache.call(void 0, ).get(stream);
|
|
1844
1368
|
const cache_hit = !!cached;
|
|
1845
|
-
let state2 = _nullishCoalesce(_optionalChain([cached, 'optionalAccess',
|
|
1846
|
-
let patches = _nullishCoalesce(_optionalChain([cached, 'optionalAccess',
|
|
1847
|
-
let snaps = _nullishCoalesce(_optionalChain([cached, 'optionalAccess',
|
|
1369
|
+
let state2 = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _58 => _58.state]), () => ( (me.init ? me.init() : {})));
|
|
1370
|
+
let patches = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _59 => _59.patches]), () => ( 0));
|
|
1371
|
+
let snaps = _nullishCoalesce(_optionalChain([cached, 'optionalAccess', _60 => _60.snaps]), () => ( 0));
|
|
1848
1372
|
let replayed = 0;
|
|
1849
1373
|
let event;
|
|
1850
|
-
await
|
|
1374
|
+
await _chunkLUHPSF3Ccjs.store.call(void 0, ).query(
|
|
1851
1375
|
(raw) => {
|
|
1852
|
-
if (seeded && raw.name ===
|
|
1376
|
+
if (seeded && raw.name === _chunkYFFWCVXWcjs.SNAP_EVENT && replayed > 0) return;
|
|
1853
1377
|
event = me.view(raw, actor);
|
|
1854
|
-
if (event.name ===
|
|
1378
|
+
if (event.name === _chunkYFFWCVXWcjs.SNAP_EVENT) {
|
|
1855
1379
|
state2 = event.data;
|
|
1856
1380
|
snaps++;
|
|
1857
1381
|
patches = 0;
|
|
@@ -1860,12 +1384,12 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1860
1384
|
state2 = patch_fn(me, state2, me.patch[event.name](event, state2), event);
|
|
1861
1385
|
patches++;
|
|
1862
1386
|
replayed++;
|
|
1863
|
-
} else if (event.name !==
|
|
1864
|
-
|
|
1387
|
+
} else if (event.name !== _chunkYFFWCVXWcjs.TOMBSTONE_EVENT) {
|
|
1388
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).warn(
|
|
1865
1389
|
`Skipping unknown event "${String(event.name)}" on stream "${stream}" (id=${event.id}) \u2014 no reducer in state "${me.name}"`
|
|
1866
1390
|
);
|
|
1867
1391
|
}
|
|
1868
|
-
_optionalChain([callback, 'optionalCall',
|
|
1392
|
+
_optionalChain([callback, 'optionalCall', _61 => _61({
|
|
1869
1393
|
event,
|
|
1870
1394
|
state: state2,
|
|
1871
1395
|
version: event.version,
|
|
@@ -1889,7 +1413,7 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1889
1413
|
) : time_travel ? asOf : { with_snaps: true }
|
|
1890
1414
|
}
|
|
1891
1415
|
);
|
|
1892
|
-
const head_is_tombstone = _optionalChain([event, 'optionalAccess',
|
|
1416
|
+
const head_is_tombstone = _optionalChain([event, 'optionalAccess', _62 => _62.name]) === _chunkYFFWCVXWcjs.TOMBSTONE_EVENT;
|
|
1893
1417
|
if (replayed > 0 && !time_travel && event && !me.pii_aware && !head_is_tombstone) {
|
|
1894
1418
|
await cache_put(stream, {
|
|
1895
1419
|
stream,
|
|
@@ -1903,23 +1427,56 @@ async function load(me, target, callback, patch_fn = bare_patch) {
|
|
|
1903
1427
|
return {
|
|
1904
1428
|
event,
|
|
1905
1429
|
state: state2,
|
|
1906
|
-
version: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess',
|
|
1430
|
+
version: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _63 => _63.version]), () => ( _optionalChain([cached, 'optionalAccess', _64 => _64.version]))), () => ( -1)),
|
|
1907
1431
|
// Captured with `state`, so consumers never race a separate cache lookup.
|
|
1908
|
-
id: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess',
|
|
1432
|
+
id: _nullishCoalesce(_nullishCoalesce(_optionalChain([event, 'optionalAccess', _65 => _65.id]), () => ( _optionalChain([cached, 'optionalAccess', _66 => _66.event_id]))), () => ( -1)),
|
|
1909
1433
|
patches,
|
|
1910
1434
|
snaps,
|
|
1911
1435
|
cache_hit,
|
|
1912
1436
|
replayed
|
|
1913
1437
|
};
|
|
1914
1438
|
}
|
|
1439
|
+
async function load_others(loads, payload, own, actor, patch_fn, refuse) {
|
|
1440
|
+
const streams = loads.map((l) => l.target(payload, own.state));
|
|
1441
|
+
streams.forEach((stream, i) => {
|
|
1442
|
+
if (stream === void 0) return;
|
|
1443
|
+
if (typeof stream !== "string" || !stream)
|
|
1444
|
+
throw refuse(`loads "${loads[i].name}" from an empty stream name`);
|
|
1445
|
+
if (stream === own.stream) throw refuse(`loads its own stream "${stream}"`);
|
|
1446
|
+
if (streams.indexOf(stream) !== i)
|
|
1447
|
+
throw refuse(`loads stream "${stream}" twice`);
|
|
1448
|
+
});
|
|
1449
|
+
return Promise.all(
|
|
1450
|
+
loads.map(async (l, i) => {
|
|
1451
|
+
const stream = streams[i];
|
|
1452
|
+
if (stream === void 0) return void 0;
|
|
1453
|
+
const snapshot = await load(
|
|
1454
|
+
l.state,
|
|
1455
|
+
{ stream, actor },
|
|
1456
|
+
void 0,
|
|
1457
|
+
patch_fn
|
|
1458
|
+
);
|
|
1459
|
+
if (_optionalChain([snapshot, 'access', _67 => _67.event, 'optionalAccess', _68 => _68.name]) === _chunkYFFWCVXWcjs.TOMBSTONE_EVENT)
|
|
1460
|
+
throw new (0, _chunkYFFWCVXWcjs.StreamClosedError)(stream);
|
|
1461
|
+
return {
|
|
1462
|
+
state: l.state,
|
|
1463
|
+
stream,
|
|
1464
|
+
snapshot,
|
|
1465
|
+
expected: snapshot.version,
|
|
1466
|
+
events: []
|
|
1467
|
+
};
|
|
1468
|
+
})
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1915
1471
|
async function action(me, action2, target, payload, options, patch_fn = bare_patch) {
|
|
1916
1472
|
const { stream, expectedVersion, actor } = target;
|
|
1917
1473
|
if (!stream) throw new Error("Missing target stream");
|
|
1918
|
-
const reactingTo = _optionalChain([options, 'optionalAccess',
|
|
1919
|
-
const correlator = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1920
|
-
const validated =
|
|
1921
|
-
const opts = _optionalChain([me, 'access',
|
|
1922
|
-
const max_retries = _nullishCoalesce(_optionalChain([opts, 'optionalAccess',
|
|
1474
|
+
const reactingTo = _optionalChain([options, 'optionalAccess', _69 => _69.reactingTo]);
|
|
1475
|
+
const correlator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _70 => _70.correlator]), () => ( default_correlator));
|
|
1476
|
+
const validated = _chunkLUHPSF3Ccjs.validate.call(void 0, action2, payload, me.actions[action2]);
|
|
1477
|
+
const opts = _optionalChain([me, 'access', _71 => _71.options, 'optionalAccess', _72 => _72[action2]]);
|
|
1478
|
+
const max_retries = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _73 => _73.maxRetries]), () => ( 0));
|
|
1479
|
+
const loads = _nullishCoalesce(_optionalChain([me, 'access', _74 => _74.loads, 'optionalAccess', _75 => _75[action2]]), () => ( []));
|
|
1923
1480
|
for (let attempt = 0; ; attempt++) {
|
|
1924
1481
|
try {
|
|
1925
1482
|
const snapshot = await load(
|
|
@@ -1928,38 +1485,68 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
|
|
|
1928
1485
|
void 0,
|
|
1929
1486
|
patch_fn
|
|
1930
1487
|
);
|
|
1931
|
-
if (_optionalChain([snapshot, 'access',
|
|
1932
|
-
throw new (0,
|
|
1933
|
-
const
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1488
|
+
if (_optionalChain([snapshot, 'access', _76 => _76.event, 'optionalAccess', _77 => _77.name]) === _chunkYFFWCVXWcjs.TOMBSTONE_EVENT)
|
|
1489
|
+
throw new (0, _chunkYFFWCVXWcjs.StreamClosedError)(stream);
|
|
1490
|
+
const own = {
|
|
1491
|
+
state: me,
|
|
1492
|
+
stream,
|
|
1493
|
+
snapshot,
|
|
1494
|
+
expected: _nullishCoalesce(expectedVersion, () => ( snapshot.version)),
|
|
1495
|
+
events: []
|
|
1496
|
+
};
|
|
1497
|
+
const others = loads.length ? await load_others(
|
|
1498
|
+
loads,
|
|
1499
|
+
validated,
|
|
1500
|
+
{ stream, state: snapshot.state },
|
|
1501
|
+
target.actor,
|
|
1502
|
+
patch_fn,
|
|
1503
|
+
(description) => new (0, _chunkYFFWCVXWcjs.PreconditionError)(
|
|
1504
|
+
action2,
|
|
1505
|
+
validated,
|
|
1506
|
+
target,
|
|
1507
|
+
snapshot,
|
|
1508
|
+
description
|
|
1509
|
+
)
|
|
1510
|
+
) : [];
|
|
1511
|
+
const loaded = Object.fromEntries(
|
|
1512
|
+
others.map((p, i) => [loads[i].name, _optionalChain([p, 'optionalAccess', _78 => _78.snapshot, 'access', _79 => _79.state])])
|
|
1513
|
+
);
|
|
1514
|
+
for (const { holds, description } of _nullishCoalesce(_optionalChain([me, 'access', _80 => _80.requires, 'optionalAccess', _81 => _81[action2]]), () => ( [])))
|
|
1515
|
+
if (!holds(validated, snapshot.state, actor, loaded))
|
|
1516
|
+
throw new (0, _chunkYFFWCVXWcjs.PreconditionError)(
|
|
1946
1517
|
action2,
|
|
1947
1518
|
validated,
|
|
1948
1519
|
target,
|
|
1949
1520
|
snapshot,
|
|
1950
1521
|
description
|
|
1951
1522
|
);
|
|
1952
|
-
const result = me.on[action2](validated, snapshot, target);
|
|
1523
|
+
const result = me.on[action2](validated, snapshot, target, loaded);
|
|
1953
1524
|
if (!result || Array.isArray(result) && !result.length)
|
|
1954
1525
|
return [snapshot];
|
|
1955
1526
|
const tuples = Array.isArray(result[0]) ? result : [result];
|
|
1956
|
-
const
|
|
1957
|
-
name
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1527
|
+
for (const [name, data] of tuples) {
|
|
1528
|
+
const event = name;
|
|
1529
|
+
const i = loads.findIndex((l) => l.events.includes(event));
|
|
1530
|
+
if (i >= 0 && !others[i]) continue;
|
|
1531
|
+
const to = i >= 0 ? others[i] : name in me.events ? own : void 0;
|
|
1532
|
+
if (!to)
|
|
1533
|
+
throw new Error(
|
|
1534
|
+
`Action "${action2}" emitted "${event}", which isn't an event of "${me.name}" and isn't listed on any of its loads`
|
|
1535
|
+
);
|
|
1536
|
+
to.events.push({
|
|
1537
|
+
name: event,
|
|
1538
|
+
data: _chunkLUHPSF3Ccjs.validate.call(void 0, event, data, to.state.events[event])
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
if (!own.events.length)
|
|
1542
|
+
throw new Error(
|
|
1543
|
+
`Action "${action2}" appends only to the streams it loads; it must append an event to its own stream too`
|
|
1544
|
+
);
|
|
1545
|
+
const appends = [own, ...others].filter(
|
|
1546
|
+
(p) => !!_optionalChain([p, 'optionalAccess', _82 => _82.events, 'access', _83 => _83.length])
|
|
1547
|
+
);
|
|
1961
1548
|
const meta = {
|
|
1962
|
-
correlation: _optionalChain([reactingTo, 'optionalAccess',
|
|
1549
|
+
correlation: _optionalChain([reactingTo, 'optionalAccess', _84 => _84.meta, 'access', _85 => _85.correlation]) || correlator({
|
|
1963
1550
|
action: action2,
|
|
1964
1551
|
state: me.name,
|
|
1965
1552
|
stream,
|
|
@@ -1978,72 +1565,97 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
|
|
|
1978
1565
|
} : void 0
|
|
1979
1566
|
}
|
|
1980
1567
|
};
|
|
1981
|
-
let { state: state2, patches } = snapshot;
|
|
1982
1568
|
const created = /* @__PURE__ */ new Date();
|
|
1983
|
-
const
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1569
|
+
const folds = appends.map((p) => {
|
|
1570
|
+
let { state: state2, patches } = p.snapshot;
|
|
1571
|
+
const folded = p.events.map((e, i) => {
|
|
1572
|
+
const event = {
|
|
1573
|
+
...e,
|
|
1574
|
+
id: -1,
|
|
1575
|
+
stream: p.stream,
|
|
1576
|
+
version: p.snapshot.version + i + 1,
|
|
1577
|
+
created,
|
|
1578
|
+
meta
|
|
1579
|
+
};
|
|
1580
|
+
const patch2 = p.state.patch[event.name](event, state2);
|
|
1581
|
+
state2 = patch_fn(p.state, state2, patch2, event);
|
|
1582
|
+
patches++;
|
|
1583
|
+
return { state: state2, patch: patch2, patches };
|
|
1584
|
+
});
|
|
1585
|
+
check_invariants(
|
|
1586
|
+
`${p.state.name}.${action2}`,
|
|
1587
|
+
state2,
|
|
1588
|
+
p.state.state,
|
|
1589
|
+
p.state.pii_aware
|
|
1590
|
+
);
|
|
1591
|
+
return folded;
|
|
1996
1592
|
});
|
|
1997
|
-
check_invariants(
|
|
1998
|
-
`${me.name}.${action2}`,
|
|
1999
|
-
state2,
|
|
2000
|
-
me.state,
|
|
2001
|
-
me.pii_aware
|
|
2002
|
-
);
|
|
2003
1593
|
let committed;
|
|
2004
1594
|
try {
|
|
2005
|
-
committed = await
|
|
1595
|
+
committed = await _chunkLUHPSF3Ccjs.store.call(void 0, ).commit(
|
|
1596
|
+
appends.map((p) => ({
|
|
1597
|
+
stream: p.stream,
|
|
1598
|
+
msgs: p.events.map((e) => p.state.message(e)),
|
|
1599
|
+
expectedVersion: p.expected
|
|
1600
|
+
})),
|
|
1601
|
+
meta
|
|
1602
|
+
);
|
|
2006
1603
|
} catch (error) {
|
|
2007
|
-
if (error instanceof
|
|
1604
|
+
if (error instanceof _chunkYFFWCVXWcjs.ConcurrencyError) void cache_drop(error.stream);
|
|
2008
1605
|
throw error;
|
|
2009
1606
|
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
event_id: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _98 => _98.id]), () => ( last.event.id)),
|
|
2029
|
-
patches: snap_event ? 0 : last.patches,
|
|
2030
|
-
snaps: snap_event ? last.snaps + 1 : last.snaps
|
|
1607
|
+
let row = 0;
|
|
1608
|
+
const snapshots = [];
|
|
1609
|
+
for (const [a, append] of appends.entries()) {
|
|
1610
|
+
const { snapshot: base, state: owner } = append;
|
|
1611
|
+
const appended = append.events.map((e, i) => {
|
|
1612
|
+
const stored = committed[row++];
|
|
1613
|
+
const fold = folds[a][i];
|
|
1614
|
+
return {
|
|
1615
|
+
event: { ...stored, data: e.data },
|
|
1616
|
+
state: fold.state,
|
|
1617
|
+
version: stored.version,
|
|
1618
|
+
id: stored.id,
|
|
1619
|
+
patches: fold.patches,
|
|
1620
|
+
snaps: base.snaps,
|
|
1621
|
+
patch: fold.patch,
|
|
1622
|
+
cache_hit: base.cache_hit,
|
|
1623
|
+
replayed: base.replayed
|
|
1624
|
+
};
|
|
2031
1625
|
});
|
|
1626
|
+
const last = appended.at(-1);
|
|
1627
|
+
const snap_event = _optionalChain([owner, 'access', _86 => _86.snap, 'optionalCall', _87 => _87(last)]) ? await snap(last) : void 0;
|
|
1628
|
+
if (!owner.pii_aware)
|
|
1629
|
+
void cache_put(append.stream, {
|
|
1630
|
+
stream: append.stream,
|
|
1631
|
+
state: last.state,
|
|
1632
|
+
version: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _88 => _88.version]), () => ( last.event.version)),
|
|
1633
|
+
event_id: _nullishCoalesce(_optionalChain([snap_event, 'optionalAccess', _89 => _89.id]), () => ( last.event.id)),
|
|
1634
|
+
patches: snap_event ? 0 : last.patches,
|
|
1635
|
+
snaps: snap_event ? last.snaps + 1 : last.snaps
|
|
1636
|
+
});
|
|
1637
|
+
if (snap_event)
|
|
1638
|
+
appended[appended.length - 1] = {
|
|
1639
|
+
...last,
|
|
1640
|
+
version: snap_event.version
|
|
1641
|
+
};
|
|
1642
|
+
snapshots.push(...appended);
|
|
1643
|
+
}
|
|
2032
1644
|
return snapshots;
|
|
2033
1645
|
} catch (error) {
|
|
2034
|
-
if (!(error instanceof
|
|
2035
|
-
if (expectedVersion !== void 0) throw error;
|
|
1646
|
+
if (!(error instanceof _chunkYFFWCVXWcjs.ConcurrencyError)) throw error;
|
|
1647
|
+
if (expectedVersion !== void 0 && error.stream === stream) throw error;
|
|
2036
1648
|
if (attempt >= max_retries) throw error;
|
|
2037
|
-
if (_optionalChain([opts, 'optionalAccess',
|
|
1649
|
+
if (_optionalChain([opts, 'optionalAccess', _90 => _90.backoff])) {
|
|
2038
1650
|
const delay_ms = compute_backoff_delay(attempt, opts.backoff);
|
|
2039
|
-
if (delay_ms > 0) await
|
|
1651
|
+
if (delay_ms > 0) await _chunkLUHPSF3Ccjs.sleep.call(void 0, delay_ms);
|
|
2040
1652
|
}
|
|
2041
1653
|
}
|
|
2042
1654
|
}
|
|
2043
1655
|
}
|
|
2044
1656
|
|
|
2045
1657
|
// src/internal/tracing.ts
|
|
2046
|
-
var PRETTY =
|
|
1658
|
+
var PRETTY = _chunkLUHPSF3Ccjs.config.call(void 0, ).env !== "production";
|
|
2047
1659
|
var C_BLUE = "\x1B[38;5;39m";
|
|
2048
1660
|
var C_ORANGE = "\x1B[38;5;208m";
|
|
2049
1661
|
var C_GREEN = "\x1B[38;5;42m";
|
|
@@ -2089,9 +1701,9 @@ var as_of_marker = (asOf) => {
|
|
|
2089
1701
|
return parts.length ? ` (as-of ${parts.join(" ")})` : " (as-of)";
|
|
2090
1702
|
};
|
|
2091
1703
|
var traced = (inner, exit, entry) => (async (...args) => {
|
|
2092
|
-
_optionalChain([entry, 'optionalCall',
|
|
1704
|
+
_optionalChain([entry, 'optionalCall', _91 => _91(...args)]);
|
|
2093
1705
|
const result = await inner(...args);
|
|
2094
|
-
_optionalChain([exit, 'optionalCall',
|
|
1706
|
+
_optionalChain([exit, 'optionalCall', _92 => _92(result, ...args)]);
|
|
2095
1707
|
return result;
|
|
2096
1708
|
});
|
|
2097
1709
|
function build_es(logger, correlator = default_correlator, patch_fn = bare_patch) {
|
|
@@ -2100,7 +1712,7 @@ function build_es(logger, correlator = default_correlator, patch_fn = bare_patch
|
|
|
2100
1712
|
action_name,
|
|
2101
1713
|
target,
|
|
2102
1714
|
payload,
|
|
2103
|
-
{ ...options, correlator: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1715
|
+
{ ...options, correlator: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _93 => _93.correlator]), () => ( correlator)) },
|
|
2104
1716
|
patch_fn
|
|
2105
1717
|
);
|
|
2106
1718
|
const bound_load = (me, target, callback) => load(me, target, callback, patch_fn);
|
|
@@ -2139,14 +1751,14 @@ function build_es(logger, correlator = default_correlator, patch_fn = bare_patch
|
|
|
2139
1751
|
}),
|
|
2140
1752
|
action: traced(
|
|
2141
1753
|
bound_action,
|
|
2142
|
-
(snapshots
|
|
1754
|
+
(snapshots) => {
|
|
2143
1755
|
if (snapshots[0].patch)
|
|
2144
1756
|
logger.trace(
|
|
2145
1757
|
snapshots.map((s) => s.event.data),
|
|
2146
1758
|
es_caption(
|
|
2147
1759
|
"committed",
|
|
2148
1760
|
C_ORANGE,
|
|
2149
|
-
|
|
1761
|
+
snapshots.map((s) => `${s.event.stream}.${s.event.name}`).join(", ")
|
|
2150
1762
|
)
|
|
2151
1763
|
);
|
|
2152
1764
|
},
|
|
@@ -2174,7 +1786,7 @@ function build_drain(logger) {
|
|
|
2174
1786
|
subscribe: logger.level !== "trace" ? subscribe : traced(subscribe, (result, streams) => {
|
|
2175
1787
|
if (!result.subscribed) return;
|
|
2176
1788
|
const lanes = new Set(streams.map((s) => _nullishCoalesce(s.lane, () => ( "default"))));
|
|
2177
|
-
const uniform_lane = lanes.size === 1 ? _optionalChain([streams, 'access',
|
|
1789
|
+
const uniform_lane = lanes.size === 1 ? _optionalChain([streams, 'access', _94 => _94[0], 'optionalAccess', _95 => _95.lane]) : void 0;
|
|
2178
1790
|
const data = streams.map(
|
|
2179
1791
|
({ stream, lane }) => uniform_lane || !lane || lane === "default" ? hue(C_STREAM, stream) : `${hue(C_STREAM, stream)}${dim(`[${lane}]`)}`
|
|
2180
1792
|
).join(" ");
|
|
@@ -2186,7 +1798,7 @@ function build_drain(logger) {
|
|
|
2186
1798
|
}
|
|
2187
1799
|
function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
2188
1800
|
if (logger.level !== "trace" || !leased.length) return;
|
|
2189
|
-
const lane = _optionalChain([leased, 'access',
|
|
1801
|
+
const lane = _optionalChain([leased, 'access', _96 => _96[0], 'optionalAccess', _97 => _97.lane]);
|
|
2190
1802
|
const fetch_by_stream = new Map(fetched.map((f) => [f.stream, f]));
|
|
2191
1803
|
const acked_by_stream = new Map(acked.map((a) => [a.stream, a.at]));
|
|
2192
1804
|
const blocked_by_stream = new Map(blocked.map((b) => [b.stream, b.error]));
|
|
@@ -2195,8 +1807,8 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
|
2195
1807
|
);
|
|
2196
1808
|
const detail = leased.map(({ stream, at, retry }) => {
|
|
2197
1809
|
const f = fetch_by_stream.get(stream);
|
|
2198
|
-
const key = _optionalChain([f, 'optionalAccess',
|
|
2199
|
-
const events = _optionalChain([f, 'optionalAccess',
|
|
1810
|
+
const key = _optionalChain([f, 'optionalAccess', _98 => _98.source]) ? `${hue(C_STREAM, stream)}${dim(`<-${f.source}`)}` : hue(C_STREAM, stream);
|
|
1811
|
+
const events = _optionalChain([f, 'optionalAccess', _99 => _99.events, 'access', _100 => _100.length]) ? ` ${dim(
|
|
2200
1812
|
`[${f.events.map(({ id, name }) => `#${id} ${String(name)}`).join(", ")}]`
|
|
2201
1813
|
)}` : "";
|
|
2202
1814
|
const acked_at = acked_by_stream.get(stream);
|
|
@@ -2224,10 +1836,10 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
|
2224
1836
|
|
|
2225
1837
|
// src/internal/drain-cycle.ts
|
|
2226
1838
|
function budget_exhausted(lease, options, store_failing) {
|
|
2227
|
-
if (store_failing || !_optionalChain([options, 'optionalAccess',
|
|
1839
|
+
if (store_failing || !_optionalChain([options, 'optionalAccess', _101 => _101.blockOnError]) || lease.retry <= options.maxRetries)
|
|
2228
1840
|
return void 0;
|
|
2229
1841
|
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
|
-
|
|
1842
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).error(error);
|
|
2231
1843
|
return { lease, handled: 0, acked_at: lease.at, error, block: true };
|
|
2232
1844
|
}
|
|
2233
1845
|
function fetch_failure_policy(registry) {
|
|
@@ -2243,13 +1855,13 @@ function fetch_failure_policy(registry) {
|
|
|
2243
1855
|
function finalize(lease, handled, at, error, options, logger, failed_at) {
|
|
2244
1856
|
if (!error) return { lease, handled, acked_at: at };
|
|
2245
1857
|
logger.error(error);
|
|
2246
|
-
const non_retryable = error instanceof
|
|
1858
|
+
const non_retryable = error instanceof _chunkYFFWCVXWcjs.NonRetryableError;
|
|
2247
1859
|
const block2 = options.blockOnError && (non_retryable || lease.retry >= options.maxRetries);
|
|
2248
1860
|
if (block2)
|
|
2249
1861
|
logger.error(
|
|
2250
1862
|
non_retryable ? `Blocking ${lease.stream} on non-retryable error.` : `Blocking ${lease.stream} after ${lease.retry} retries.`
|
|
2251
1863
|
);
|
|
2252
|
-
const next_attempt_at = block2 ? void 0 : Date.now() + compute_backoff_delay(lease.retry, _nullishCoalesce(options.backoff, () => (
|
|
1864
|
+
const next_attempt_at = block2 ? void 0 : Date.now() + compute_backoff_delay(lease.retry, _nullishCoalesce(options.backoff, () => ( _chunkLUHPSF3Ccjs.DEFAULT_BACKOFF)));
|
|
2253
1865
|
return {
|
|
2254
1866
|
lease,
|
|
2255
1867
|
handled,
|
|
@@ -2260,275 +1872,1165 @@ function finalize(lease, handled, at, error, options, logger, failed_at) {
|
|
|
2260
1872
|
failed_at
|
|
2261
1873
|
};
|
|
2262
1874
|
}
|
|
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
|
-
);
|
|
1875
|
+
function warn_misrouted(seen, stream, handler, event) {
|
|
1876
|
+
report_once(
|
|
1877
|
+
seen,
|
|
1878
|
+
`${stream}|${handler}|${event}`,
|
|
1879
|
+
`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.`
|
|
1880
|
+
);
|
|
1881
|
+
}
|
|
1882
|
+
async function run_drain_cycle(deps, cycle) {
|
|
1883
|
+
const { ops, registry, batch_handlers, handle, handle_batch, lane } = deps;
|
|
1884
|
+
const {
|
|
1885
|
+
lagging,
|
|
1886
|
+
leading,
|
|
1887
|
+
eventLimit,
|
|
1888
|
+
leaseMillis,
|
|
1889
|
+
misrouted,
|
|
1890
|
+
store_failing
|
|
1891
|
+
} = cycle;
|
|
1892
|
+
const leased = await ops.claim(
|
|
1893
|
+
lagging,
|
|
1894
|
+
leading,
|
|
1895
|
+
_crypto.randomUUID.call(void 0, ),
|
|
1896
|
+
leaseMillis,
|
|
1897
|
+
lane
|
|
1898
|
+
);
|
|
1899
|
+
if (!leased.length) return void 0;
|
|
1900
|
+
const fetched = await ops.fetch(leased, eventLimit);
|
|
1901
|
+
const fetch_map = /* @__PURE__ */ new Map();
|
|
1902
|
+
const fetch_window_at = fetched.reduce(
|
|
1903
|
+
(max, { at, events }) => Math.max(max, _optionalChain([events, 'access', _102 => _102.at, 'call', _103 => _103(-1), 'optionalAccess', _104 => _104.id]) || at),
|
|
1904
|
+
0
|
|
1905
|
+
);
|
|
1906
|
+
for (const f of fetched) {
|
|
1907
|
+
const { stream, events } = f;
|
|
1908
|
+
let failed;
|
|
1909
|
+
const payloads = events.flatMap((event) => {
|
|
1910
|
+
const register = registry.events[event.name];
|
|
1911
|
+
if (!register) return [];
|
|
1912
|
+
return [...register.reactions.values()].filter((reaction) => {
|
|
1913
|
+
const resolver = reaction.resolver;
|
|
1914
|
+
const dynamic = typeof resolver === "function";
|
|
1915
|
+
let resolved;
|
|
1916
|
+
try {
|
|
1917
|
+
resolved = dynamic ? resolver(event) : resolver;
|
|
1918
|
+
} catch (error) {
|
|
1919
|
+
failed ??= {
|
|
1920
|
+
error: new Error(
|
|
1921
|
+
`Resolver of reaction "${reaction.handler.name}" threw on ${String(event.name)} #${event.id} (stream "${event.stream}"): ${String(error)}`
|
|
1922
|
+
),
|
|
1923
|
+
options: reaction.options
|
|
1924
|
+
};
|
|
1925
|
+
return false;
|
|
1926
|
+
}
|
|
1927
|
+
if (!resolved || resolved.target !== stream) return false;
|
|
1928
|
+
if (!dynamic || !batch_handlers.has(stream)) return true;
|
|
1929
|
+
warn_misrouted(
|
|
1930
|
+
misrouted,
|
|
1931
|
+
stream,
|
|
1932
|
+
reaction.handler.name,
|
|
1933
|
+
String(event.name)
|
|
1934
|
+
);
|
|
1935
|
+
return false;
|
|
1936
|
+
}).map((reaction) => ({ ...reaction, event }));
|
|
1937
|
+
});
|
|
1938
|
+
fetch_map.set(stream, { fetch: f, payloads, failed });
|
|
1939
|
+
}
|
|
1940
|
+
const handled = await Promise.all(
|
|
1941
|
+
leased.map((lease) => {
|
|
1942
|
+
const entry = fetch_map.get(lease.stream);
|
|
1943
|
+
if (entry.fetch.error !== void 0) {
|
|
1944
|
+
const policy = fetch_failure_policy(registry);
|
|
1945
|
+
return Promise.resolve(
|
|
1946
|
+
finalize(
|
|
1947
|
+
lease,
|
|
1948
|
+
0,
|
|
1949
|
+
lease.at,
|
|
1950
|
+
new Error(`Fetch failed for ${lease.stream}: ${entry.fetch.error}`),
|
|
1951
|
+
store_failing ? { ...policy, blockOnError: false } : policy,
|
|
1952
|
+
deps.logger
|
|
1953
|
+
)
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
if (entry.failed)
|
|
1957
|
+
return Promise.resolve(
|
|
1958
|
+
finalize(
|
|
1959
|
+
lease,
|
|
1960
|
+
0,
|
|
1961
|
+
lease.at,
|
|
1962
|
+
entry.failed.error,
|
|
1963
|
+
entry.failed.options,
|
|
1964
|
+
deps.logger
|
|
1965
|
+
)
|
|
1966
|
+
);
|
|
1967
|
+
const at = _optionalChain([entry, 'access', _105 => _105.fetch, 'access', _106 => _106.events, 'access', _107 => _107.at, 'call', _108 => _108(-1), 'optionalAccess', _109 => _109.id]) || fetch_window_at;
|
|
1968
|
+
const { payloads } = entry;
|
|
1969
|
+
const exhausted = budget_exhausted(
|
|
1970
|
+
lease,
|
|
1971
|
+
_optionalChain([payloads, 'access', _110 => _110[0], 'optionalAccess', _111 => _111.options]),
|
|
1972
|
+
store_failing
|
|
1973
|
+
);
|
|
1974
|
+
if (exhausted) return Promise.resolve(exhausted);
|
|
1975
|
+
const batchHandler = batch_handlers.get(lease.stream);
|
|
1976
|
+
if (batchHandler && payloads.length > 0) {
|
|
1977
|
+
return handle_batch({ ...lease, at }, payloads, batchHandler);
|
|
1978
|
+
}
|
|
1979
|
+
return handle({ ...lease, at }, payloads);
|
|
1980
|
+
})
|
|
1981
|
+
);
|
|
1982
|
+
const to_block = handled.filter(({ block: block2 }) => block2).map(({ lease, error }) => ({ ...lease, error }));
|
|
1983
|
+
const blocked = to_block.length ? await ops.block(to_block) : [];
|
|
1984
|
+
if (blocked.length) deps.on_blocked(blocked);
|
|
1985
|
+
const submitted = handled.flatMap((h, i) => {
|
|
1986
|
+
const advance = h.handled > 0 ? h.acked_at : leased[i].at;
|
|
1987
|
+
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 } : [];
|
|
1988
|
+
});
|
|
1989
|
+
const acked = submitted.length ? await ops.ack(submitted) : [];
|
|
1990
|
+
const expected = submitted.filter((l) => l.due === void 0).length;
|
|
1991
|
+
if (acked.length < expected)
|
|
1992
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).warn(
|
|
1993
|
+
`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.`
|
|
1994
|
+
);
|
|
1995
|
+
const closeable = handled.filter((h) => h.close !== void 0).map((h) => h.close);
|
|
1996
|
+
return { leased, fetched, handled, acked, blocked, closeable };
|
|
1997
|
+
}
|
|
1998
|
+
var EMPTY_DRAIN = {
|
|
1999
|
+
fetched: [],
|
|
2000
|
+
leased: [],
|
|
2001
|
+
acked: [],
|
|
2002
|
+
blocked: []
|
|
2003
|
+
};
|
|
2004
|
+
function merge_drains(drains) {
|
|
2005
|
+
return {
|
|
2006
|
+
fetched: drains.flatMap((d) => d.fetched),
|
|
2007
|
+
leased: drains.flatMap((d) => d.leased),
|
|
2008
|
+
acked: drains.flatMap((d) => d.acked),
|
|
2009
|
+
blocked: drains.flatMap((d) => d.blocked)
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
var RETRY = "";
|
|
2013
|
+
var DrainController = (_class3 = class {
|
|
2014
|
+
// Armed while `_raised` is ahead of `_lowered` (the raise count the last
|
|
2015
|
+
// empty claim saw), so a claim never lowers over a raise that landed
|
|
2016
|
+
// during it.
|
|
2017
|
+
__init3() {this._raised = 0}
|
|
2018
|
+
__init4() {this._lowered = 0}
|
|
2019
|
+
__init5() {this._ratio = 0.5}
|
|
2020
|
+
// Local wake at the earliest parked (backoff or defer) visit, or at the
|
|
2021
|
+
// lease expiry after a failed pass (the {@link RETRY} key); the schedule
|
|
2022
|
+
// itself is persisted. On an idle app nothing else would drain it. It
|
|
2023
|
+
// drains until a pass leases nothing or the controller stops, and an entry
|
|
2024
|
+
// stays until handled or until a later pass claims nothing.
|
|
2025
|
+
__init6() {this._defer = new DeferTimer(() => {
|
|
2026
|
+
this.arm();
|
|
2027
|
+
void this._deps.run_scoped(async () => {
|
|
2028
|
+
while ((await this.drain()).leased.length > 0) ;
|
|
2029
|
+
});
|
|
2030
|
+
})}
|
|
2031
|
+
|
|
2032
|
+
__init7() {this._misrouted = /* @__PURE__ */ new Set()}
|
|
2033
|
+
__init8() {this._stopped = false}
|
|
2034
|
+
// The pass in flight. Never rejects; graceful shutdown waits on it.
|
|
2035
|
+
|
|
2036
|
+
|
|
2037
|
+
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);
|
|
2038
|
+
this._deps = deps;
|
|
2039
|
+
}
|
|
2040
|
+
arm() {
|
|
2041
|
+
this._raised++;
|
|
2042
|
+
}
|
|
2043
|
+
/** Cold start: re-seed a persisted `deferred_at` into the local wake. */
|
|
2044
|
+
seed_defer(stream, at) {
|
|
2045
|
+
this._defer.set(stream, at);
|
|
2046
|
+
this._defer.schedule();
|
|
2047
|
+
}
|
|
2048
|
+
get armed() {
|
|
2049
|
+
return this._raised !== this._lowered;
|
|
2050
|
+
}
|
|
2051
|
+
get inflight() {
|
|
2052
|
+
return this._inflight;
|
|
2053
|
+
}
|
|
2054
|
+
/** This lane's configured lease, or `undefined`; the shutdown grace basis. */
|
|
2055
|
+
get lease_millis() {
|
|
2056
|
+
return _optionalChain([this, 'access', _112 => _112._deps, 'access', _113 => _113.defaults, 'optionalAccess', _114 => _114.leaseMillis]);
|
|
2057
|
+
}
|
|
2058
|
+
get lane() {
|
|
2059
|
+
return this._deps.lane;
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Drains every `cycleMs` while armed; the unref'd timer never holds the
|
|
2063
|
+
* process. Called once, when the controller is built.
|
|
2064
|
+
*/
|
|
2065
|
+
start(cycleMs) {
|
|
2066
|
+
const run = this._deps.run_scoped;
|
|
2067
|
+
const tick = async () => {
|
|
2068
|
+
if (this.armed) await run(() => this.drain());
|
|
2069
|
+
if (this._stopped) return;
|
|
2070
|
+
this._worker = setTimeout(tick, cycleMs);
|
|
2071
|
+
this._worker.unref();
|
|
2072
|
+
};
|
|
2073
|
+
this._worker = setTimeout(tick, cycleMs);
|
|
2074
|
+
this._worker.unref();
|
|
2075
|
+
}
|
|
2076
|
+
stop() {
|
|
2077
|
+
this._stopped = true;
|
|
2078
|
+
if (this._worker) {
|
|
2079
|
+
clearTimeout(this._worker);
|
|
2080
|
+
this._worker = void 0;
|
|
2081
|
+
}
|
|
2082
|
+
this._defer.stop();
|
|
2083
|
+
}
|
|
2084
|
+
async drain(options = {}) {
|
|
2085
|
+
if (!this.armed || this._stopped || this._inflight)
|
|
2086
|
+
return EMPTY_DRAIN;
|
|
2087
|
+
const d = _nullishCoalesce(this._deps.defaults, () => ( {}));
|
|
2088
|
+
const streamLimit = _nullishCoalesce(_nullishCoalesce(d.streamLimit, () => ( options.streamLimit)), () => ( _chunkLUHPSF3Ccjs.DEFAULT_STREAM_LIMIT));
|
|
2089
|
+
const eventLimit = _nullishCoalesce(options.eventLimit, () => ( _chunkLUHPSF3Ccjs.DEFAULT_EVENT_LIMIT));
|
|
2090
|
+
const leaseMillis = _nullishCoalesce(_nullishCoalesce(d.leaseMillis, () => ( options.leaseMillis)), () => ( _chunkLUHPSF3Ccjs.DEFAULT_LEASE_MILLIS));
|
|
2091
|
+
if (this._deps.breaker.state(Date.now()) === "open")
|
|
2092
|
+
return EMPTY_DRAIN;
|
|
2093
|
+
const pass = this._pass(streamLimit, eventLimit, leaseMillis).finally(
|
|
2094
|
+
() => {
|
|
2095
|
+
this._inflight = void 0;
|
|
2096
|
+
}
|
|
2097
|
+
);
|
|
2098
|
+
this._inflight = pass;
|
|
2099
|
+
return pass;
|
|
2100
|
+
}
|
|
2101
|
+
// One claim → fetch → handle → ack pass. Never throws.
|
|
2102
|
+
async _pass(streamLimit, eventLimit, leaseMillis) {
|
|
2103
|
+
try {
|
|
2104
|
+
const lagging = Math.ceil(streamLimit * this._ratio);
|
|
2105
|
+
const leading = streamLimit - lagging;
|
|
2106
|
+
const started = Date.now();
|
|
2107
|
+
const raised = this._raised;
|
|
2108
|
+
const cycle = await run_drain_cycle(this._deps, {
|
|
2109
|
+
lagging,
|
|
2110
|
+
leading,
|
|
2111
|
+
eventLimit,
|
|
2112
|
+
leaseMillis,
|
|
2113
|
+
misrouted: this._misrouted,
|
|
2114
|
+
store_failing: this._deps.breaker.failing
|
|
2115
|
+
});
|
|
2116
|
+
if (!cycle) {
|
|
2117
|
+
this._defer.prune(started);
|
|
2118
|
+
this._deps.breaker.passed();
|
|
2119
|
+
this._lowered = raised;
|
|
2120
|
+
return EMPTY_DRAIN;
|
|
2121
|
+
}
|
|
2122
|
+
const { leased, fetched, handled, acked, blocked, closeable } = cycle;
|
|
2123
|
+
trace_cycle(this._deps.logger, leased, fetched, handled, acked, blocked);
|
|
2124
|
+
this._ratio = compute_lag_lead_ratio(handled, lagging, leading);
|
|
2125
|
+
for (const lease of acked) this._defer.delete(lease.stream);
|
|
2126
|
+
for (const lease of blocked) this._defer.delete(lease.stream);
|
|
2127
|
+
for (const h of handled) {
|
|
2128
|
+
const next = _nullishCoalesce(h.defer, () => ( h.next_attempt_at));
|
|
2129
|
+
if (next !== void 0) this._defer.set(h.lease.stream, next);
|
|
2130
|
+
}
|
|
2131
|
+
if (acked.length) this._deps.on_acked(acked);
|
|
2132
|
+
if (closeable.length) await this._deps.on_close(closeable);
|
|
2133
|
+
this._deps.breaker.passed();
|
|
2134
|
+
return { fetched, leased, acked, blocked };
|
|
2135
|
+
} catch (error) {
|
|
2136
|
+
this._defer.set(
|
|
2137
|
+
RETRY,
|
|
2138
|
+
Date.now() + Math.max(leaseMillis, this._deps.breaker.cooldown_ms)
|
|
2139
|
+
);
|
|
2140
|
+
this._deps.breaker.failed(Date.now(), error);
|
|
2141
|
+
return EMPTY_DRAIN;
|
|
2142
|
+
} finally {
|
|
2143
|
+
if (!this._stopped) this._defer.schedule();
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}, _class3);
|
|
2147
|
+
|
|
2148
|
+
// src/internal/reaction-dispatch.ts
|
|
2149
|
+
var CloseSignal = class extends Error {
|
|
2150
|
+
/**
|
|
2151
|
+
* Stream to close. Omitted → the reaction's own lease stream (a self-close).
|
|
2152
|
+
* The synthesized autoclose reaction sets it to the aggregate stream, since
|
|
2153
|
+
* its lease runs on a synthetic `__autoclose__` target.
|
|
2154
|
+
*/
|
|
2155
|
+
|
|
2156
|
+
/** Optional archive callback to run while the stream is guarded. */
|
|
2157
|
+
|
|
2158
|
+
/**
|
|
2159
|
+
* Watermark to ack the requesting reaction to before the close runs. The
|
|
2160
|
+
* close-cycle safety guard skips a stream whose subscriptions (matched by
|
|
2161
|
+
* source) lag the head; the autoclose reaction's `source` is the aggregate,
|
|
2162
|
+
* so it must advance its own watermark to the live head id it evaluated
|
|
2163
|
+
* against — otherwise it blocks its own close. Defaults to the triggering
|
|
2164
|
+
* event id when omitted.
|
|
2165
|
+
*/
|
|
2166
|
+
|
|
2167
|
+
/**
|
|
2168
|
+
* Windowed close: prune events older than this cutoff behind
|
|
2169
|
+
* the closest safe snapshot instead of retiring the stream. Thrown by
|
|
2170
|
+
* the autoclose reaction of a `.autocloses({ keep })` state; flows
|
|
2171
|
+
* into {@link CloseTarget.before}. Omitted → a full close.
|
|
2172
|
+
*/
|
|
2173
|
+
|
|
2174
|
+
/**
|
|
2175
|
+
* Revisit the requesting reaction at this time. Only useful with an `at`
|
|
2176
|
+
* below the head: a reaction runs only when an event is waiting for it.
|
|
2177
|
+
*/
|
|
2178
|
+
|
|
2179
|
+
constructor(opts) {
|
|
2180
|
+
super("reaction requested close");
|
|
2181
|
+
this.name = "CloseSignal";
|
|
2182
|
+
this.stream = _optionalChain([opts, 'optionalAccess', _115 => _115.stream]);
|
|
2183
|
+
this.archive = _optionalChain([opts, 'optionalAccess', _116 => _116.archive]);
|
|
2184
|
+
this.at = _optionalChain([opts, 'optionalAccess', _117 => _117.at]);
|
|
2185
|
+
this.before = _optionalChain([opts, 'optionalAccess', _118 => _118.before]);
|
|
2186
|
+
this.defer = _optionalChain([opts, 'optionalAccess', _119 => _119.defer]);
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
function build_handle(deps) {
|
|
2190
|
+
const { logger, reaction_scope } = deps;
|
|
2191
|
+
return async (lease, payloads) => {
|
|
2192
|
+
if (payloads.length === 0) return { lease, handled: 0, acked_at: lease.at };
|
|
2193
|
+
const stream = lease.stream;
|
|
2194
|
+
const last_index_of = /* @__PURE__ */ new Map();
|
|
2195
|
+
for (let i = 0; i < payloads.length; i++)
|
|
2196
|
+
last_index_of.set(payloads[i].event.id, i);
|
|
2197
|
+
let at = lease.at;
|
|
2198
|
+
let handled = 0;
|
|
2199
|
+
if (lease.retry > 0)
|
|
2200
|
+
logger.warn(
|
|
2201
|
+
`Retrying ${stream}@${payloads.at(0).event.id} (${lease.retry}).`
|
|
2202
|
+
);
|
|
2203
|
+
for (let i = 0; i < payloads.length; i++) {
|
|
2204
|
+
const payload = payloads[i];
|
|
2205
|
+
const { event, handler } = payload;
|
|
2206
|
+
try {
|
|
2207
|
+
await reaction_scope.run(
|
|
2208
|
+
event,
|
|
2209
|
+
() => handler(event, stream, reaction_scope.app)
|
|
2210
|
+
);
|
|
2211
|
+
if (last_index_of.get(event.id) === i) {
|
|
2212
|
+
at = event.id;
|
|
2213
|
+
handled++;
|
|
2214
|
+
}
|
|
2215
|
+
} catch (error) {
|
|
2216
|
+
if (error instanceof _chunkYFFWCVXWcjs.DeferSignal) {
|
|
2217
|
+
let defer;
|
|
2218
|
+
try {
|
|
2219
|
+
defer = resolve_defer_at(error.when, event);
|
|
2220
|
+
} catch (invalid) {
|
|
2221
|
+
return finalize(
|
|
2222
|
+
lease,
|
|
2223
|
+
handled,
|
|
2224
|
+
at,
|
|
2225
|
+
invalid,
|
|
2226
|
+
payload.options,
|
|
2227
|
+
logger,
|
|
2228
|
+
event.id
|
|
2229
|
+
);
|
|
2230
|
+
}
|
|
2231
|
+
return { lease, handled, acked_at: at, defer };
|
|
2232
|
+
}
|
|
2233
|
+
if (error instanceof CloseSignal)
|
|
2234
|
+
return {
|
|
2235
|
+
lease,
|
|
2236
|
+
handled: handled + 1,
|
|
2237
|
+
// Advance to the live head the handler evaluated against (when
|
|
2238
|
+
// provided) so the close-cycle guard sees this reaction caught up.
|
|
2239
|
+
acked_at: _nullishCoalesce(error.at, () => ( event.id)),
|
|
2240
|
+
defer: _optionalChain([error, 'access', _120 => _120.defer, 'optionalAccess', _121 => _121.getTime, 'call', _122 => _122()]),
|
|
2241
|
+
// Close the signalled stream (the autoclose reaction's aggregate,
|
|
2242
|
+
// which differs from its synthetic lease stream); a self-closing
|
|
2243
|
+
// user reaction omits it and closes its own lease stream. A
|
|
2244
|
+
// carried `before` makes it a windowed close (prune, not retire).
|
|
2245
|
+
close: {
|
|
2246
|
+
stream: _nullishCoalesce(error.stream, () => ( stream)),
|
|
2247
|
+
archive: error.archive,
|
|
2248
|
+
before: error.before
|
|
2249
|
+
}
|
|
2250
|
+
};
|
|
2251
|
+
return finalize(
|
|
2252
|
+
lease,
|
|
2253
|
+
handled,
|
|
2254
|
+
at,
|
|
2255
|
+
error,
|
|
2256
|
+
payload.options,
|
|
2257
|
+
logger,
|
|
2258
|
+
event.id
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
return finalize(lease, handled, at, void 0, payloads[0].options, logger);
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
function build_handle_batch(logger) {
|
|
2266
|
+
return async (lease, payloads, batchHandler) => {
|
|
2267
|
+
const stream = lease.stream;
|
|
2268
|
+
const events = [];
|
|
2269
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2270
|
+
for (const p of payloads) {
|
|
2271
|
+
if (seen.has(p.event.id)) continue;
|
|
2272
|
+
seen.add(p.event.id);
|
|
2273
|
+
events.push(p.event);
|
|
2274
|
+
}
|
|
2275
|
+
const options = payloads[0].options;
|
|
2276
|
+
if (lease.retry > 0)
|
|
2277
|
+
logger.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);
|
|
2278
|
+
try {
|
|
2279
|
+
await batchHandler(events, stream);
|
|
2280
|
+
return finalize(
|
|
2281
|
+
lease,
|
|
2282
|
+
events.length,
|
|
2283
|
+
events.at(-1).id,
|
|
2284
|
+
void 0,
|
|
2285
|
+
options,
|
|
2286
|
+
logger
|
|
2287
|
+
);
|
|
2288
|
+
} catch (error) {
|
|
2289
|
+
return finalize(lease, 0, lease.at, error, options, logger);
|
|
2290
|
+
}
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// src/internal/autoclose-reaction.ts
|
|
2295
|
+
var AUTOCLOSE_TARGET_PREFIX = "__autoclose__:";
|
|
2296
|
+
function synthesize_autoclose_reactions(registry, states, read_window) {
|
|
2297
|
+
for (const st of states.values()) {
|
|
2298
|
+
const predicate = st.autoclose;
|
|
2299
|
+
if (!predicate) continue;
|
|
2300
|
+
const after_windows = st.autoclose_after_windows;
|
|
2301
|
+
const keep_days = st.autoclose_keep_days;
|
|
2302
|
+
const archiver = st.archive;
|
|
2303
|
+
const reaction = {
|
|
2304
|
+
// Run on a SYNTHETIC stream — `source` is the aggregate, `target` is a
|
|
2305
|
+
// per-aggregate `__autoclose__` key — so the autoclose reaction never
|
|
2306
|
+
// shares a watermark with the aggregate's own reactions. A shared
|
|
2307
|
+
// watermark would let autoclose's defer short-circuit the aggregate's
|
|
2308
|
+
// other reactions (the "a defer affects all reactions on a stream"
|
|
2309
|
+
// hazard). The close still targets the aggregate (`source`).
|
|
2310
|
+
// An anchored stream name would read as a pattern, and a store may refuse
|
|
2311
|
+
// it at subscribe, stopping every reaction. Such a stream has no
|
|
2312
|
+
// autoclose: `app.close` still closes it.
|
|
2313
|
+
resolver: (e) => _chunkLUHPSF3Ccjs.is_literal_source.call(void 0, e.stream) ? {
|
|
2314
|
+
target: `${AUTOCLOSE_TARGET_PREFIX}${e.stream}`,
|
|
2315
|
+
source: e.stream
|
|
2316
|
+
} : void 0,
|
|
2317
|
+
// Never block on autoclose: a transient query/store error should retry,
|
|
2318
|
+
// not quarantine the synthetic stream.
|
|
2319
|
+
options: { blockOnError: false, maxRetries: _chunkLUHPSF3Ccjs.DEFAULT_MAX_RETRIES },
|
|
2320
|
+
handler: async (event) => {
|
|
2321
|
+
const aggregate = event.stream;
|
|
2322
|
+
const window = read_window();
|
|
2323
|
+
if (!in_autoclose_window(window, /* @__PURE__ */ new Date()))
|
|
2324
|
+
throw new (0, _chunkYFFWCVXWcjs.DeferSignal)({ at: next_window_open(window, /* @__PURE__ */ new Date()) });
|
|
2325
|
+
const stats = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_stats([aggregate], {
|
|
2326
|
+
count: true,
|
|
2327
|
+
tail: keep_days !== void 0 ? true : void 0,
|
|
2328
|
+
exclude: [_chunkYFFWCVXWcjs.TOMBSTONE_EVENT, _chunkYFFWCVXWcjs.SNAP_EVENT]
|
|
2329
|
+
});
|
|
2330
|
+
const entry = stats.get(aggregate);
|
|
2331
|
+
if (!entry) return;
|
|
2332
|
+
const head = entry.head;
|
|
2333
|
+
if (predicate(aggregate, head, entry.count))
|
|
2334
|
+
throw new CloseSignal({
|
|
2335
|
+
stream: aggregate,
|
|
2336
|
+
archive: archiver ? () => archiver(aggregate, head) : void 0,
|
|
2337
|
+
// Ack this reaction's own watermark to the live head so the
|
|
2338
|
+
// close-cycle guard (which matches subscriptions by source =
|
|
2339
|
+
// aggregate) sees it caught up instead of blocking its own close.
|
|
2340
|
+
at: head.id
|
|
2341
|
+
});
|
|
2342
|
+
if (keep_days !== void 0) {
|
|
2343
|
+
const cutoff = days_before_now(keep_days);
|
|
2344
|
+
if (entry.tail.created < cutoff) {
|
|
2345
|
+
const waiting = after_windows.some(
|
|
2346
|
+
(days) => days_after(head.created, days).getTime() > Date.now()
|
|
2347
|
+
);
|
|
2348
|
+
throw new CloseSignal({
|
|
2349
|
+
stream: aggregate,
|
|
2350
|
+
before: cutoff,
|
|
2351
|
+
archive: archiver ? () => archiver(aggregate, head, cutoff) : void 0,
|
|
2352
|
+
at: waiting ? head.id - 1 : head.id,
|
|
2353
|
+
defer: waiting ? days_after(/* @__PURE__ */ new Date(), 1) : void 0
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
const dues = [];
|
|
2358
|
+
for (const days of after_windows)
|
|
2359
|
+
dues.push(days_after(head.created, days));
|
|
2360
|
+
if (keep_days !== void 0)
|
|
2361
|
+
dues.push(days_after(entry.tail.created, keep_days));
|
|
2362
|
+
const future = dues.map((d) => d.getTime()).filter((t) => t > Date.now());
|
|
2363
|
+
if (future.length)
|
|
2364
|
+
throw new (0, _chunkYFFWCVXWcjs.DeferSignal)({ at: new Date(Math.min(...future)) });
|
|
2365
|
+
}
|
|
2366
|
+
};
|
|
2367
|
+
const key = `__autoclose_${st.name}`;
|
|
2368
|
+
for (const event_name of Object.keys(st.events)) {
|
|
2369
|
+
_optionalChain([registry, 'access', _123 => _123.events, 'access', _124 => _124[event_name], 'optionalAccess', _125 => _125.reactions, 'access', _126 => _126.set, 'call', _127 => _127(
|
|
2370
|
+
key,
|
|
2371
|
+
reaction
|
|
2372
|
+
)]);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
// src/internal/close-cycle.ts
|
|
2378
|
+
var CLOSE_CATCH_UP_LIMIT = 1e3;
|
|
2379
|
+
var CLOSE_CATCH_UP_PASSES = 20;
|
|
2380
|
+
async function catch_up_correlation(cursor, correlate, until) {
|
|
2381
|
+
for (let pass = 0; pass < CLOSE_CATCH_UP_PASSES && cursor.checkpoint < until; pass++) {
|
|
2382
|
+
const before = cursor.checkpoint;
|
|
2383
|
+
cursor.arm();
|
|
2384
|
+
await correlate(CLOSE_CATCH_UP_LIMIT);
|
|
2385
|
+
if (cursor.checkpoint <= before) break;
|
|
2386
|
+
}
|
|
2387
|
+
return cursor.checkpoint;
|
|
2388
|
+
}
|
|
2389
|
+
var CloseLock = (_class4 = class {constructor() { _class4.prototype.__init9.call(this); }
|
|
2390
|
+
__init9() {this._tails = /* @__PURE__ */ new Map()}
|
|
2391
|
+
/** Run `work` after every earlier close of `stream` has settled. */
|
|
2392
|
+
run(stream, work) {
|
|
2393
|
+
const prev = _nullishCoalesce(this._tails.get(stream), () => ( Promise.resolve()));
|
|
2394
|
+
const next = prev.then(work, work);
|
|
2395
|
+
this._tails.set(stream, next);
|
|
2396
|
+
const cleanup = () => {
|
|
2397
|
+
if (this._tails.get(stream) === next) this._tails.delete(stream);
|
|
2398
|
+
};
|
|
2399
|
+
next.then(cleanup, cleanup);
|
|
2400
|
+
return next;
|
|
2401
|
+
}
|
|
2402
|
+
}, _class4);
|
|
2403
|
+
var SAFETY_PROBE_PAGE_SIZE = 1e3;
|
|
2404
|
+
async function run_close_cycle(targets, deps) {
|
|
2405
|
+
const target_map = new Map(targets.map((t) => [t.stream, t]));
|
|
2406
|
+
for (const t of target_map.values()) {
|
|
2407
|
+
if (t.before !== void 0 && t.restart)
|
|
2408
|
+
throw new Error(
|
|
2409
|
+
`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`
|
|
2410
|
+
);
|
|
2411
|
+
}
|
|
2412
|
+
const windowed = [...target_map.values()].filter(
|
|
2413
|
+
(t) => t.before !== void 0
|
|
2414
|
+
);
|
|
2415
|
+
const full = [...target_map.values()].filter((t) => t.before === void 0);
|
|
2416
|
+
const skipped = [];
|
|
2417
|
+
const windowed_result = windowed.length ? await run_windowed_closes(windowed, deps, skipped) : /* @__PURE__ */ new Map();
|
|
2418
|
+
if (!full.length) return { truncated: windowed_result, skipped };
|
|
2419
|
+
const truncated = await with_stream_locks(
|
|
2420
|
+
full.map((t) => t.stream),
|
|
2421
|
+
deps,
|
|
2422
|
+
() => run_full_closes(full, target_map, deps, skipped)
|
|
2423
|
+
);
|
|
2424
|
+
const retired = [...truncated.entries()].filter(([, r]) => r.committed.name === _chunkYFFWCVXWcjs.TOMBSTONE_EVENT).map(([stream]) => stream);
|
|
2425
|
+
if (retired.length) _optionalChain([deps, 'access', _128 => _128.forget_subscribed, 'optionalCall', _129 => _129(retired)]);
|
|
2426
|
+
for (const [stream, entry] of windowed_result) truncated.set(stream, entry);
|
|
2427
|
+
return { truncated, skipped };
|
|
2428
|
+
}
|
|
2429
|
+
function with_stream_locks(streams, deps, work) {
|
|
2430
|
+
const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, w) => w())));
|
|
2431
|
+
return [...streams].sort().reduceRight(
|
|
2432
|
+
(inner, stream) => () => with_lock(stream, inner),
|
|
2433
|
+
work
|
|
2434
|
+
)();
|
|
2435
|
+
}
|
|
2436
|
+
async function run_full_closes(full, target_map, deps, skipped) {
|
|
2437
|
+
const none = /* @__PURE__ */ new Map();
|
|
2438
|
+
const streams = full.map((t) => t.stream);
|
|
2439
|
+
const stream_info = await scan_stream_heads(streams);
|
|
2440
|
+
for (const target of full) {
|
|
2441
|
+
if (!target.restart) continue;
|
|
2442
|
+
const info = stream_info.get(target.stream);
|
|
2443
|
+
if (!info) continue;
|
|
2444
|
+
const owner = deps.event_to_state.get(info.last_event_name);
|
|
2445
|
+
if (_optionalChain([owner, 'optionalAccess', _130 => _130.pii_aware])) {
|
|
2446
|
+
deps.logger.error(
|
|
2447
|
+
`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.`
|
|
2448
|
+
);
|
|
2449
|
+
skipped.push(target.stream);
|
|
2450
|
+
stream_info.delete(target.stream);
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
const safe = await partition_by_safety(
|
|
2454
|
+
stream_info,
|
|
2455
|
+
deps.reactive,
|
|
2456
|
+
skipped,
|
|
2457
|
+
_nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
|
|
2458
|
+
deps.catch_up_correlation
|
|
2459
|
+
);
|
|
2460
|
+
if (!safe.length) return none;
|
|
2461
|
+
const { guarded, guard_events } = await guard_with_tombstones(
|
|
2462
|
+
safe,
|
|
2463
|
+
stream_info,
|
|
2464
|
+
deps.correlation,
|
|
2465
|
+
deps.tombstone,
|
|
2466
|
+
skipped
|
|
2467
|
+
);
|
|
2468
|
+
if (!guarded.length) return none;
|
|
2469
|
+
const seed_states = await load_restart_seeds(
|
|
2470
|
+
guarded,
|
|
2471
|
+
target_map,
|
|
2472
|
+
stream_info,
|
|
2473
|
+
deps.event_to_state,
|
|
2474
|
+
deps.load,
|
|
2475
|
+
deps.logger
|
|
2476
|
+
);
|
|
2477
|
+
await run_archive_callbacks(guarded, target_map);
|
|
2478
|
+
const still_guarded = await heads_still_guarded(
|
|
2479
|
+
guarded,
|
|
2480
|
+
guard_events,
|
|
2481
|
+
skipped
|
|
2482
|
+
);
|
|
2483
|
+
if (!still_guarded.length) return none;
|
|
2484
|
+
return truncate_and_warm_cache(
|
|
2485
|
+
still_guarded,
|
|
2486
|
+
seed_states,
|
|
2487
|
+
guard_events,
|
|
2488
|
+
deps.correlation
|
|
2489
|
+
);
|
|
2490
|
+
}
|
|
2491
|
+
async function run_windowed_closes(windowed, deps, skipped) {
|
|
2492
|
+
const checkpoint = deps.reactive ? await deps.catch_up_correlation(Number.MAX_SAFE_INTEGER) : -1;
|
|
2493
|
+
const min_at = deps.reactive ? await probe_min_watermarks(
|
|
2494
|
+
windowed.map((t) => t.stream),
|
|
2495
|
+
_nullishCoalesce(deps.probe_page_size, () => ( SAFETY_PROBE_PAGE_SIZE)),
|
|
2496
|
+
checkpoint
|
|
2497
|
+
) : /* @__PURE__ */ new Map();
|
|
2498
|
+
const with_lock = _nullishCoalesce(deps.with_stream_lock, () => ( ((_stream, work) => work())));
|
|
2499
|
+
const truncated = /* @__PURE__ */ new Map();
|
|
2500
|
+
for (const t of windowed) {
|
|
2501
|
+
const entry = await with_lock(t.stream, async () => {
|
|
2502
|
+
const max_id = min_at.get(t.stream);
|
|
2503
|
+
if (!await windowed_prune_pending(t.stream, t.before, max_id))
|
|
2504
|
+
return void 0;
|
|
2505
|
+
if (t.archive) await t.archive();
|
|
2506
|
+
const result = await _chunkLUHPSF3Ccjs.store.call(void 0, ).truncate([
|
|
2507
|
+
{ stream: t.stream, before: t.before, max_id }
|
|
2508
|
+
]);
|
|
2509
|
+
return result.get(t.stream);
|
|
2510
|
+
});
|
|
2511
|
+
if (entry) truncated.set(t.stream, entry);
|
|
2512
|
+
else skipped.push(t.stream);
|
|
2513
|
+
}
|
|
2514
|
+
return truncated;
|
|
2515
|
+
}
|
|
2516
|
+
async function windowed_prune_pending(stream, before, max_id) {
|
|
2517
|
+
let boundary_id;
|
|
2518
|
+
let min_id;
|
|
2519
|
+
await _chunkLUHPSF3Ccjs.store.call(void 0, ).query(
|
|
2520
|
+
(event) => {
|
|
2521
|
+
if (min_id === void 0 || event.id < min_id) min_id = event.id;
|
|
2522
|
+
if (event.name === _chunkYFFWCVXWcjs.SNAP_EVENT && event.created < before && (max_id === void 0 || event.id <= max_id) && (boundary_id === void 0 || event.id > boundary_id))
|
|
2523
|
+
boundary_id = event.id;
|
|
2524
|
+
},
|
|
2525
|
+
{ stream, stream_exact: true, with_snaps: true, after: -1 }
|
|
2526
|
+
);
|
|
2527
|
+
return boundary_id !== void 0 && min_id < boundary_id;
|
|
2528
|
+
}
|
|
2529
|
+
async function probe_min_watermarks(streams, page_size, checkpoint) {
|
|
2530
|
+
const min_at = /* @__PURE__ */ new Map();
|
|
2531
|
+
const matches = source_matcher();
|
|
2532
|
+
await walk_streams(
|
|
2533
|
+
_chunkLUHPSF3Ccjs.store.call(void 0, ),
|
|
2534
|
+
(position) => {
|
|
2535
|
+
const pending = position.correlated_at === void 0 || position.at < position.correlated_at;
|
|
2536
|
+
const cap = pending ? position.at : Math.max(position.at, checkpoint);
|
|
2537
|
+
for (const stream of streams) {
|
|
2538
|
+
if (matches(position.source, position.stream, stream)) {
|
|
2539
|
+
const prev = min_at.get(stream);
|
|
2540
|
+
if (prev === void 0 || cap < prev) min_at.set(stream, cap);
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
},
|
|
2544
|
+
{ limit: page_size }
|
|
2545
|
+
);
|
|
2546
|
+
return min_at;
|
|
2547
|
+
}
|
|
2548
|
+
function source_matcher() {
|
|
2549
|
+
const compiled = /* @__PURE__ */ new Map();
|
|
2550
|
+
return (source, target, stream) => {
|
|
2551
|
+
if (!source) return true;
|
|
2552
|
+
if (_chunkLUHPSF3Ccjs.is_literal_source.call(void 0, source, target)) return source === stream;
|
|
2553
|
+
let re = compiled.get(source);
|
|
2554
|
+
if (!re) {
|
|
2555
|
+
re = new RegExp(source);
|
|
2556
|
+
compiled.set(source, re);
|
|
2557
|
+
}
|
|
2558
|
+
return re.test(stream);
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
async function scan_stream_heads(streams) {
|
|
2562
|
+
const stats = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_stats(streams, {
|
|
2563
|
+
exclude: [_chunkYFFWCVXWcjs.SNAP_EVENT]
|
|
2564
|
+
});
|
|
2565
|
+
const domain_heads = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_stats(streams, {
|
|
2566
|
+
exclude: [_chunkYFFWCVXWcjs.SNAP_EVENT, _chunkYFFWCVXWcjs.TOMBSTONE_EVENT]
|
|
2567
|
+
});
|
|
2568
|
+
const true_heads = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_stats(streams, {});
|
|
2569
|
+
const out = /* @__PURE__ */ new Map();
|
|
2570
|
+
for (const [stream, { head }] of domain_heads) {
|
|
2571
|
+
const marker_head = _optionalChain([stats, 'access', _131 => _131.get, 'call', _132 => _132(stream), 'optionalAccess', _133 => _133.head]);
|
|
2572
|
+
const interrupted = _optionalChain([marker_head, 'optionalAccess', _134 => _134.name]) === _chunkYFFWCVXWcjs.TOMBSTONE_EVENT;
|
|
2573
|
+
out.set(stream, {
|
|
2574
|
+
max_id: head.id,
|
|
2575
|
+
version: true_heads.get(stream).head.version,
|
|
2576
|
+
last_event_name: head.name,
|
|
2577
|
+
...interrupted ? { resumed_guard: { id: marker_head.id } } : {}
|
|
2578
|
+
});
|
|
2579
|
+
}
|
|
2580
|
+
return out;
|
|
2269
2581
|
}
|
|
2270
|
-
async function
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
}
|
|
2280
|
-
const
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2582
|
+
async function partition_by_safety(stream_info, reactive, skipped, page_size, catch_up_correlation2) {
|
|
2583
|
+
if (!reactive) return [...stream_info.keys()];
|
|
2584
|
+
let needed = -1;
|
|
2585
|
+
for (const info of stream_info.values())
|
|
2586
|
+
needed = Math.max(needed, info.max_id);
|
|
2587
|
+
const checkpoint = await catch_up_correlation2(needed);
|
|
2588
|
+
const uncorrelated = /* @__PURE__ */ new Set();
|
|
2589
|
+
for (const [stream, info] of stream_info) {
|
|
2590
|
+
if (checkpoint < info.max_id) uncorrelated.add(stream);
|
|
2591
|
+
}
|
|
2592
|
+
const pending_set = /* @__PURE__ */ new Set();
|
|
2593
|
+
const matches = source_matcher();
|
|
2594
|
+
await walk_streams(
|
|
2595
|
+
_chunkLUHPSF3Ccjs.store.call(void 0, ),
|
|
2596
|
+
(position) => {
|
|
2597
|
+
const has_work = position.correlated_at !== void 0 && position.at < position.correlated_at;
|
|
2598
|
+
if (!has_work) return;
|
|
2599
|
+
if (position.stream.startsWith(AUTOCLOSE_TARGET_PREFIX)) return;
|
|
2600
|
+
for (const [stream, info] of stream_info) {
|
|
2601
|
+
if (matches(position.source, position.stream, stream) && position.at < info.max_id)
|
|
2602
|
+
pending_set.add(stream);
|
|
2603
|
+
}
|
|
2604
|
+
},
|
|
2605
|
+
{ limit: page_size }
|
|
2293
2606
|
);
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
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;
|
|
2314
|
-
}
|
|
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 });
|
|
2607
|
+
const safe = [];
|
|
2608
|
+
for (const [stream] of stream_info) {
|
|
2609
|
+
if (pending_set.has(stream) || uncorrelated.has(stream))
|
|
2610
|
+
skipped.push(stream);
|
|
2611
|
+
else safe.push(stream);
|
|
2327
2612
|
}
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
deps.logger
|
|
2341
|
-
)
|
|
2342
|
-
);
|
|
2613
|
+
return safe;
|
|
2614
|
+
}
|
|
2615
|
+
async function guard_with_tombstones(safe, stream_info, correlation, tombstone2, skipped) {
|
|
2616
|
+
const guarded = [];
|
|
2617
|
+
const guard_events = /* @__PURE__ */ new Map();
|
|
2618
|
+
await Promise.all(
|
|
2619
|
+
safe.map(async (stream) => {
|
|
2620
|
+
const info = stream_info.get(stream);
|
|
2621
|
+
if (info.resumed_guard) {
|
|
2622
|
+
guarded.push(stream);
|
|
2623
|
+
guard_events.set(stream, { id: info.resumed_guard.id, stream });
|
|
2624
|
+
return;
|
|
2343
2625
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2626
|
+
const committed = await tombstone2(stream, info.version, correlation);
|
|
2627
|
+
if (committed) {
|
|
2628
|
+
guarded.push(stream);
|
|
2629
|
+
guard_events.set(stream, { id: committed.id, stream });
|
|
2630
|
+
} else {
|
|
2631
|
+
skipped.push(stream);
|
|
2632
|
+
}
|
|
2633
|
+
})
|
|
2634
|
+
);
|
|
2635
|
+
return { guarded, guard_events };
|
|
2636
|
+
}
|
|
2637
|
+
async function load_restart_seeds(guarded, target_map, stream_info, event_to_state, load2, logger) {
|
|
2638
|
+
const seed_states = /* @__PURE__ */ new Map();
|
|
2639
|
+
await Promise.all(
|
|
2640
|
+
guarded.filter((s) => _optionalChain([target_map, 'access', _135 => _135.get, 'call', _136 => _136(s), 'optionalAccess', _137 => _137.restart])).map(async (stream) => {
|
|
2641
|
+
const last_event_name = stream_info.get(stream).last_event_name;
|
|
2642
|
+
const owner_state = event_to_state.get(last_event_name);
|
|
2643
|
+
if (!owner_state) {
|
|
2644
|
+
logger.error(
|
|
2645
|
+
`Cannot seed restart for "${stream}": no registered state owns event "${last_event_name}". Stream will be tombstoned instead.`
|
|
2354
2646
|
);
|
|
2355
|
-
|
|
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);
|
|
2647
|
+
return;
|
|
2366
2648
|
}
|
|
2367
|
-
|
|
2649
|
+
const snap2 = await load2(owner_state, { stream });
|
|
2650
|
+
seed_states.set(stream, snap2.state);
|
|
2368
2651
|
})
|
|
2369
2652
|
);
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
const
|
|
2374
|
-
const
|
|
2375
|
-
|
|
2653
|
+
return seed_states;
|
|
2654
|
+
}
|
|
2655
|
+
async function run_archive_callbacks(guarded, target_map) {
|
|
2656
|
+
for (const stream of guarded) {
|
|
2657
|
+
const archive_fn = _optionalChain([target_map, 'access', _138 => _138.get, 'call', _139 => _139(stream), 'optionalAccess', _140 => _140.archive]);
|
|
2658
|
+
if (archive_fn) await archive_fn();
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
async function heads_still_guarded(guarded, guard_events, skipped) {
|
|
2662
|
+
const heads = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_stats(guarded, {});
|
|
2663
|
+
return guarded.filter((stream) => {
|
|
2664
|
+
if (_optionalChain([heads, 'access', _141 => _141.get, 'call', _142 => _142(stream), 'optionalAccess', _143 => _143.head, 'access', _144 => _144.id]) === guard_events.get(stream).id)
|
|
2665
|
+
return true;
|
|
2666
|
+
skipped.push(stream);
|
|
2667
|
+
return false;
|
|
2376
2668
|
});
|
|
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 };
|
|
2385
2669
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2670
|
+
async function truncate_and_warm_cache(guarded, seed_states, guard_events, correlation) {
|
|
2671
|
+
const trunc_targets = guarded.map((stream) => {
|
|
2672
|
+
const snapshot = seed_states.get(stream);
|
|
2673
|
+
const guard = guard_events.get(stream);
|
|
2674
|
+
return {
|
|
2675
|
+
stream,
|
|
2676
|
+
snapshot,
|
|
2677
|
+
meta: {
|
|
2678
|
+
correlation,
|
|
2679
|
+
causation: {
|
|
2680
|
+
event: { id: guard.id, name: _chunkYFFWCVXWcjs.TOMBSTONE_EVENT, stream: guard.stream }
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
};
|
|
2684
|
+
});
|
|
2685
|
+
const truncated = await _chunkLUHPSF3Ccjs.store.call(void 0, ).truncate(trunc_targets);
|
|
2686
|
+
await Promise.all(
|
|
2687
|
+
guarded.map(async (stream) => {
|
|
2688
|
+
const entry = truncated.get(stream);
|
|
2689
|
+
const state2 = seed_states.get(stream);
|
|
2690
|
+
if (state2 && entry) {
|
|
2691
|
+
await _chunkLUHPSF3Ccjs.cache.call(void 0, ).set(stream, {
|
|
2692
|
+
stream,
|
|
2693
|
+
state: state2,
|
|
2694
|
+
version: entry.committed.version,
|
|
2695
|
+
event_id: entry.committed.id,
|
|
2696
|
+
patches: 0,
|
|
2697
|
+
snaps: 1
|
|
2698
|
+
});
|
|
2699
|
+
} else {
|
|
2700
|
+
await _chunkLUHPSF3Ccjs.cache.call(void 0, ).invalidate(stream);
|
|
2701
|
+
}
|
|
2702
|
+
})
|
|
2703
|
+
);
|
|
2704
|
+
return truncated;
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
// src/internal/correlate-cycle.ts
|
|
2708
|
+
|
|
2709
|
+
var COLD_START_BACK_SCAN = 1e4;
|
|
2710
|
+
var CORRELATION_LEASE_MS = 5e3;
|
|
2711
|
+
var registry_key = (events) => {
|
|
2712
|
+
const shape = Object.keys(events).filter((name) => events[name].reactions.size > 0).sort().map((name) => [name, [...events[name].reactions.keys()].sort()]);
|
|
2713
|
+
return _crypto.createHash.call(void 0, "sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 32);
|
|
2391
2714
|
};
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2715
|
+
var PATTERN_CACHE_SIZE = 32;
|
|
2716
|
+
function report_undeclared_lane(seen, handler, target, lane, declared) {
|
|
2717
|
+
report_once(
|
|
2718
|
+
seen,
|
|
2719
|
+
`lane|${handler}|${lane}`,
|
|
2720
|
+
`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.`
|
|
2721
|
+
);
|
|
2399
2722
|
}
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
//
|
|
2410
|
-
|
|
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
|
-
})}
|
|
2723
|
+
function report_lane_conflict(seen, handler, target, kept, dropped) {
|
|
2724
|
+
report_once(
|
|
2725
|
+
seen,
|
|
2726
|
+
`conflict|${handler}|${kept}|${dropped}`,
|
|
2727
|
+
`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.`
|
|
2728
|
+
);
|
|
2729
|
+
}
|
|
2730
|
+
var CorrelateCycle = (_class5 = class {
|
|
2731
|
+
__init10() {this._checkpoint = -1}
|
|
2732
|
+
// Lease holder id; per instance, so a restart never inherits a stale claim.
|
|
2733
|
+
__init11() {this._by = _crypto.randomUUID.call(void 0, )}
|
|
2419
2734
|
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
//
|
|
2735
|
+
// Local expiry of the held lease (0 = none); stale only costs a duplicate scan.
|
|
2736
|
+
__init12() {this._lease_until = 0}
|
|
2737
|
+
// Armed while `_raised` (bumped by a commit or notification) is ahead of
|
|
2738
|
+
// `_lowered` (the raise count the last short page saw). Starts armed.
|
|
2739
|
+
__init13() {this._raised = 1}
|
|
2740
|
+
__init14() {this._lowered = 0}
|
|
2741
|
+
// Bumped by a release (shutdown), so a scan or lease reply that was out
|
|
2742
|
+
// across one writes nothing.
|
|
2743
|
+
__init15() {this._epoch = 0}
|
|
2744
|
+
// Passes in flight: a restore waits for them, and refuses new ones.
|
|
2745
|
+
__init16() {this._passes = /* @__PURE__ */ new Set()}
|
|
2746
|
+
__init17() {this._restoring = false}
|
|
2747
|
+
|
|
2748
|
+
// Bounded by `maxSubscribedStreams`; static records live apart so eviction
|
|
2749
|
+
// never lets a resolution re-lane them.
|
|
2423
2750
|
|
|
2751
|
+
__init18() {this._static_subscriptions = /* @__PURE__ */ new Map()}
|
|
2752
|
+
__init19() {this._patterns = new (0, _chunkLUHPSF3Ccjs.LruMap)(PATTERN_CACHE_SIZE)}
|
|
2424
2753
|
|
|
2425
|
-
|
|
2426
|
-
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
|
|
2757
|
+
|
|
2758
|
+
// Report-once keys; per instance because `internal/` holds no module state.
|
|
2759
|
+
__init20() {this._reported = /* @__PURE__ */ new Set()}
|
|
2760
|
+
constructor({
|
|
2761
|
+
registry,
|
|
2762
|
+
static_targets,
|
|
2763
|
+
cd,
|
|
2764
|
+
max_subscribed_streams,
|
|
2765
|
+
declared_lanes,
|
|
2766
|
+
shard,
|
|
2767
|
+
on_init
|
|
2768
|
+
}) {;_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);
|
|
2769
|
+
this._key = shard ? `${registry_key(registry.events)}:${[...shard].sort().join(",")}` : registry_key(registry.events);
|
|
2770
|
+
this._dynamic_subscriptions = new (0, _chunkLUHPSF3Ccjs.LruMap)(max_subscribed_streams);
|
|
2771
|
+
this._registry = registry;
|
|
2772
|
+
this._declared_lanes = declared_lanes;
|
|
2773
|
+
this._static_targets = static_targets;
|
|
2774
|
+
this._cd = cd;
|
|
2775
|
+
this._on_init = on_init;
|
|
2776
|
+
}
|
|
2777
|
+
get checkpoint() {
|
|
2778
|
+
return this._checkpoint;
|
|
2427
2779
|
}
|
|
2780
|
+
/** A commit (local or remote) may have produced uncorrelated events. */
|
|
2428
2781
|
arm() {
|
|
2429
2782
|
this._raised++;
|
|
2430
2783
|
}
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2784
|
+
async _init() {
|
|
2785
|
+
this._init_promise ??= this._run_init().catch((error) => {
|
|
2786
|
+
this._init_promise = void 0;
|
|
2787
|
+
throw error;
|
|
2788
|
+
});
|
|
2789
|
+
await this._init_promise;
|
|
2435
2790
|
}
|
|
2436
|
-
|
|
2437
|
-
|
|
2791
|
+
async _run_init() {
|
|
2792
|
+
const { watermark, correlated_at } = await this._cd.subscribe([
|
|
2793
|
+
...this._static_targets
|
|
2794
|
+
]);
|
|
2795
|
+
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - COLD_START_BACK_SCAN);
|
|
2796
|
+
for (const { stream, priority = 0, lane } of this._static_targets) {
|
|
2797
|
+
this._static_subscriptions.set(stream, {
|
|
2798
|
+
priority,
|
|
2799
|
+
lane
|
|
2800
|
+
});
|
|
2801
|
+
}
|
|
2802
|
+
await _optionalChain([this, 'access', _145 => _145._on_init, 'optionalCall', _146 => _146()]);
|
|
2438
2803
|
}
|
|
2439
|
-
|
|
2440
|
-
|
|
2804
|
+
/**
|
|
2805
|
+
* Replace the log with no pass in flight, then cold-start: a pass that
|
|
2806
|
+
* read the old log writes before the restore, never into the new one.
|
|
2807
|
+
*/
|
|
2808
|
+
async restart(restore) {
|
|
2809
|
+
this._restoring = true;
|
|
2810
|
+
try {
|
|
2811
|
+
await Promise.allSettled(this._passes);
|
|
2812
|
+
await restore();
|
|
2813
|
+
} finally {
|
|
2814
|
+
this._restoring = false;
|
|
2815
|
+
}
|
|
2816
|
+
this._init_promise = void 0;
|
|
2817
|
+
this._checkpoint = -1;
|
|
2818
|
+
this._dynamic_subscriptions.clear();
|
|
2819
|
+
this._static_subscriptions.clear();
|
|
2441
2820
|
}
|
|
2442
|
-
/**
|
|
2443
|
-
|
|
2444
|
-
|
|
2821
|
+
/** Forget dynamic targets whose rows a full close deleted, so they re-subscribe. */
|
|
2822
|
+
forget_subscribed(streams) {
|
|
2823
|
+
for (const stream of streams) this._dynamic_subscriptions.delete(stream);
|
|
2445
2824
|
}
|
|
2446
|
-
|
|
2447
|
-
|
|
2825
|
+
// Would the target's own `fetch` (filtered by `source`) return this event?
|
|
2826
|
+
_in_fetch_window(source, stream) {
|
|
2827
|
+
if (source === void 0 || source === stream) return true;
|
|
2828
|
+
if (_chunkLUHPSF3Ccjs.is_literal_source.call(void 0, source)) return false;
|
|
2829
|
+
let pattern = this._patterns.get(source);
|
|
2830
|
+
if (!pattern) {
|
|
2831
|
+
pattern = new RegExp(source);
|
|
2832
|
+
this._patterns.set(source, pattern);
|
|
2833
|
+
}
|
|
2834
|
+
return pattern.test(stream);
|
|
2448
2835
|
}
|
|
2449
|
-
/**
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
this._worker.unref();
|
|
2460
|
-
};
|
|
2461
|
-
this._worker = setTimeout(tick, cycleMs);
|
|
2462
|
-
this._worker.unref();
|
|
2836
|
+
/** Scan past the checkpoint, subscribe new targets and raise their work marks. */
|
|
2837
|
+
async correlate(limit, lease = false) {
|
|
2838
|
+
if (this._restoring) return { kind: "idle", last_id: this._checkpoint };
|
|
2839
|
+
const pass = this._scan(limit, lease);
|
|
2840
|
+
this._passes.add(pass);
|
|
2841
|
+
try {
|
|
2842
|
+
return await pass;
|
|
2843
|
+
} finally {
|
|
2844
|
+
this._passes.delete(pass);
|
|
2845
|
+
}
|
|
2463
2846
|
}
|
|
2464
|
-
|
|
2465
|
-
this.
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2847
|
+
async _scan(limit, lease) {
|
|
2848
|
+
await this._init();
|
|
2849
|
+
const epoch = this._epoch;
|
|
2850
|
+
const idle = () => ({
|
|
2851
|
+
kind: "idle",
|
|
2852
|
+
last_id: this._checkpoint
|
|
2853
|
+
});
|
|
2854
|
+
if (this._raised === this._lowered) return idle();
|
|
2855
|
+
const raised = this._raised;
|
|
2856
|
+
const now = Date.now();
|
|
2857
|
+
if (lease && now >= this._lease_until - CORRELATION_LEASE_MS / 2) {
|
|
2858
|
+
const { correlating } = await this._cd.subscribe([], void 0, {
|
|
2859
|
+
key: this._key,
|
|
2860
|
+
by: this._by,
|
|
2861
|
+
millis: CORRELATION_LEASE_MS
|
|
2862
|
+
});
|
|
2863
|
+
if (this._epoch !== epoch) return idle();
|
|
2864
|
+
this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
|
|
2865
|
+
if (correlating === false) return idle();
|
|
2866
|
+
}
|
|
2867
|
+
const after = this._checkpoint;
|
|
2868
|
+
const correlated = /* @__PURE__ */ new Map();
|
|
2869
|
+
let last_id = after;
|
|
2870
|
+
let stopped = false;
|
|
2871
|
+
const found = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query(
|
|
2872
|
+
(event) => {
|
|
2873
|
+
if (stopped) return;
|
|
2874
|
+
const register = this._registry.events[event.name];
|
|
2875
|
+
if (register) {
|
|
2876
|
+
for (const reaction of register.reactions.values()) {
|
|
2877
|
+
let resolved;
|
|
2878
|
+
try {
|
|
2879
|
+
resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
2880
|
+
} catch (error) {
|
|
2881
|
+
stopped = true;
|
|
2882
|
+
report_once(
|
|
2883
|
+
this._reported,
|
|
2884
|
+
`resolver|${reaction.handler.name}|${event.id}`,
|
|
2885
|
+
`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.`
|
|
2886
|
+
);
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
if (!resolved) continue;
|
|
2890
|
+
let lane = resolved.lane;
|
|
2891
|
+
if (lane !== void 0 && !this._declared_lanes.has(lane)) {
|
|
2892
|
+
report_undeclared_lane(
|
|
2893
|
+
this._reported,
|
|
2894
|
+
reaction.handler.name,
|
|
2895
|
+
resolved.target,
|
|
2896
|
+
lane,
|
|
2897
|
+
this._declared_lanes
|
|
2898
|
+
);
|
|
2899
|
+
lane = void 0;
|
|
2900
|
+
}
|
|
2901
|
+
const fixed = this._static_subscriptions.get(resolved.target);
|
|
2902
|
+
const recorded = _nullishCoalesce(fixed, () => ( this._dynamic_subscriptions.get(resolved.target)));
|
|
2903
|
+
const priority = _nullishCoalesce(resolved.priority, () => ( 0));
|
|
2904
|
+
const upgraded = !recorded || !fixed && priority > recorded.priority;
|
|
2905
|
+
const carried = upgraded ? { priority, lane } : { priority: recorded.priority, lane: recorded.lane };
|
|
2906
|
+
const entry = correlated.get(resolved.target) || {
|
|
2907
|
+
source: resolved.source,
|
|
2908
|
+
priority: carried.priority,
|
|
2909
|
+
lane: carried.lane,
|
|
2910
|
+
upgraded,
|
|
2911
|
+
missed: !recorded,
|
|
2912
|
+
handler: reaction.handler.name,
|
|
2913
|
+
correlated_at: void 0
|
|
2914
|
+
};
|
|
2915
|
+
const seen_in_scan = correlated.has(resolved.target);
|
|
2916
|
+
const held_lane = _nullishCoalesce((seen_in_scan ? entry.lane : _optionalChain([recorded, 'optionalAccess', _147 => _147.lane])), () => ( _chunkYFFWCVXWcjs.DEFAULT_LANE));
|
|
2917
|
+
const held_priority = seen_in_scan ? entry.priority : _optionalChain([recorded, 'optionalAccess', _148 => _148.priority]);
|
|
2918
|
+
const resolved_lane = _nullishCoalesce(lane, () => ( _chunkYFFWCVXWcjs.DEFAULT_LANE));
|
|
2919
|
+
if (held_priority === priority && held_lane !== resolved_lane)
|
|
2920
|
+
report_lane_conflict(
|
|
2921
|
+
this._reported,
|
|
2922
|
+
reaction.handler.name,
|
|
2923
|
+
resolved.target,
|
|
2924
|
+
held_lane,
|
|
2925
|
+
resolved_lane
|
|
2926
|
+
);
|
|
2927
|
+
if (carried.priority > entry.priority) {
|
|
2928
|
+
entry.priority = carried.priority;
|
|
2929
|
+
entry.lane = carried.lane;
|
|
2930
|
+
entry.upgraded = upgraded;
|
|
2931
|
+
entry.handler = reaction.handler.name;
|
|
2932
|
+
}
|
|
2933
|
+
if (this._in_fetch_window(resolved.source, event.stream))
|
|
2934
|
+
entry.correlated_at = event.id;
|
|
2935
|
+
correlated.set(resolved.target, entry);
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
last_id = event.id;
|
|
2939
|
+
},
|
|
2940
|
+
// Resolvers see `pii: null`: correlate runs actor-less, and one
|
|
2941
|
+
// undecryptable row would otherwise stop every stream's reactions.
|
|
2942
|
+
{ after, limit, with_pii: false }
|
|
2943
|
+
);
|
|
2944
|
+
if (this._declared_lanes.size > 1) await this._recall(correlated);
|
|
2945
|
+
const read = last_id > after;
|
|
2946
|
+
if (this._epoch !== epoch) return idle();
|
|
2947
|
+
const streams = [];
|
|
2948
|
+
for (const [stream, entry] of correlated) {
|
|
2949
|
+
if (entry.upgraded || entry.correlated_at !== void 0)
|
|
2950
|
+
streams.push({
|
|
2951
|
+
stream,
|
|
2952
|
+
source: entry.source,
|
|
2953
|
+
priority: entry.priority,
|
|
2954
|
+
lane: entry.lane,
|
|
2955
|
+
correlated_at: entry.correlated_at
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
if (streams.length) {
|
|
2959
|
+
const renewed_at = Date.now();
|
|
2960
|
+
const { subscribed, correlating } = await this._cd.subscribe(
|
|
2961
|
+
streams,
|
|
2962
|
+
last_id,
|
|
2963
|
+
lease ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
|
|
2964
|
+
);
|
|
2965
|
+
if (lease && correlating !== false)
|
|
2966
|
+
this._lease_until = renewed_at + CORRELATION_LEASE_MS;
|
|
2967
|
+
const marked = streams.filter(
|
|
2968
|
+
(entry) => entry.correlated_at !== void 0
|
|
2969
|
+
).length;
|
|
2970
|
+
this._checkpoint = last_id;
|
|
2971
|
+
for (const { stream, priority, lane } of streams) {
|
|
2972
|
+
if (_optionalChain([correlated, 'access', _149 => _149.get, 'call', _150 => _150(stream), 'optionalAccess', _151 => _151.upgraded]))
|
|
2973
|
+
this._dynamic_subscriptions.set(stream, {
|
|
2974
|
+
priority,
|
|
2975
|
+
lane
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
return { kind: "scanned", last_id, subscribed, marked, read };
|
|
2469
2979
|
}
|
|
2470
|
-
this.
|
|
2980
|
+
this._checkpoint = last_id;
|
|
2981
|
+
if (!stopped && found !== limit) this._lowered = raised;
|
|
2982
|
+
return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
|
|
2471
2983
|
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
const
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2984
|
+
// Read the row of each target this scan had no record of (new or evicted),
|
|
2985
|
+
// so a resolution that doesn't beat its priority keeps the row's lane.
|
|
2986
|
+
// Only called with more than one lane declared.
|
|
2987
|
+
async _recall(correlated) {
|
|
2988
|
+
const missed = [...correlated].filter(([, entry]) => entry.missed);
|
|
2989
|
+
await Promise.all(
|
|
2990
|
+
missed.map(async ([stream, entry]) => {
|
|
2991
|
+
let row;
|
|
2992
|
+
await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_streams(
|
|
2993
|
+
(position) => {
|
|
2994
|
+
row = position;
|
|
2995
|
+
},
|
|
2996
|
+
{ stream, stream_exact: true, limit: 1 }
|
|
2997
|
+
);
|
|
2998
|
+
if (!row) return;
|
|
2999
|
+
this._dynamic_subscriptions.set(stream, {
|
|
3000
|
+
priority: row.priority,
|
|
3001
|
+
lane: row.lane
|
|
3002
|
+
});
|
|
3003
|
+
if (entry.priority > row.priority) return;
|
|
3004
|
+
const held_lane = _nullishCoalesce(row.lane, () => ( _chunkYFFWCVXWcjs.DEFAULT_LANE));
|
|
3005
|
+
const resolved_lane = _nullishCoalesce(entry.lane, () => ( _chunkYFFWCVXWcjs.DEFAULT_LANE));
|
|
3006
|
+
if (entry.priority === row.priority && held_lane !== resolved_lane)
|
|
3007
|
+
report_lane_conflict(
|
|
3008
|
+
this._reported,
|
|
3009
|
+
entry.handler,
|
|
3010
|
+
stream,
|
|
3011
|
+
held_lane,
|
|
3012
|
+
resolved_lane
|
|
3013
|
+
);
|
|
3014
|
+
entry.priority = row.priority;
|
|
3015
|
+
entry.lane = row.lane;
|
|
3016
|
+
entry.upgraded = false;
|
|
3017
|
+
})
|
|
2485
3018
|
);
|
|
2486
|
-
this._inflight = pass;
|
|
2487
|
-
return pass;
|
|
2488
3019
|
}
|
|
2489
|
-
|
|
2490
|
-
async
|
|
3020
|
+
/** Release the lease early by re-acquiring it for zero ms. Best-effort. */
|
|
3021
|
+
async release_correlation() {
|
|
2491
3022
|
try {
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
leading,
|
|
2499
|
-
eventLimit,
|
|
2500
|
-
leaseMillis,
|
|
2501
|
-
misrouted: this._misrouted,
|
|
2502
|
-
store_failing: this._deps.breaker.failing
|
|
3023
|
+
this._lease_until = 0;
|
|
3024
|
+
this._epoch++;
|
|
3025
|
+
await this._cd.subscribe([], void 0, {
|
|
3026
|
+
key: this._key,
|
|
3027
|
+
by: this._by,
|
|
3028
|
+
millis: 0
|
|
2503
3029
|
});
|
|
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
3030
|
} catch (error) {
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
Date.now() + Math.max(leaseMillis, this._deps.breaker.cooldown_ms)
|
|
3031
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).warn(
|
|
3032
|
+
`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
3033
|
);
|
|
2528
|
-
this._deps.breaker.failed(Date.now(), error);
|
|
2529
|
-
return EMPTY_DRAIN;
|
|
2530
|
-
} finally {
|
|
2531
|
-
if (!this._stopped) this._defer.schedule();
|
|
2532
3034
|
}
|
|
2533
3035
|
}
|
|
2534
3036
|
}, _class5);
|
|
@@ -2550,7 +3052,7 @@ function pii_gate(event, fields, predicate, actor) {
|
|
|
2550
3052
|
const { pii, ...rest } = event;
|
|
2551
3053
|
if (pii == null) {
|
|
2552
3054
|
const shredded = { ...data };
|
|
2553
|
-
for (const f of fields) shredded[f] =
|
|
3055
|
+
for (const f of fields) shredded[f] = _chunkYFFWCVXWcjs.SHREDDED;
|
|
2554
3056
|
return { ...rest, data: shredded };
|
|
2555
3057
|
}
|
|
2556
3058
|
const allowed = !!actor && !!predicate && predicate(event, actor);
|
|
@@ -2561,7 +3063,7 @@ function pii_gate(event, fields, predicate, actor) {
|
|
|
2561
3063
|
};
|
|
2562
3064
|
}
|
|
2563
3065
|
const redacted = { ...data };
|
|
2564
|
-
for (const f of fields) redacted[f] =
|
|
3066
|
+
for (const f of fields) redacted[f] = _chunkYFFWCVXWcjs.REDACTED;
|
|
2565
3067
|
return { ...rest, data: redacted };
|
|
2566
3068
|
}
|
|
2567
3069
|
var IDENTITY_GATE = (event) => event;
|
|
@@ -2657,191 +3159,15 @@ function make_fold_handler(me, flush, config2, sensitive_fields) {
|
|
|
2657
3159
|
} else {
|
|
2658
3160
|
fold.dirty = true;
|
|
2659
3161
|
}
|
|
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
|
|
2812
|
-
);
|
|
3162
|
+
if (++folded_since_flush >= config2.flushEvery) {
|
|
3163
|
+
await flush_dirty();
|
|
3164
|
+
folded_since_flush = 0;
|
|
2813
3165
|
}
|
|
2814
3166
|
}
|
|
2815
|
-
|
|
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
|
-
}
|
|
3167
|
+
await flush_dirty();
|
|
2844
3168
|
};
|
|
3169
|
+
Object.defineProperty(handler, FOLD_RESET, { value: () => cache2.clear() });
|
|
3170
|
+
return handler;
|
|
2845
3171
|
}
|
|
2846
3172
|
|
|
2847
3173
|
// src/internal/settle.ts
|
|
@@ -2882,7 +3208,7 @@ var SettleLoop = (_class6 = class {
|
|
|
2882
3208
|
this._pending = true;
|
|
2883
3209
|
return;
|
|
2884
3210
|
}
|
|
2885
|
-
const delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3211
|
+
const delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _152 => _152.debounceMs]), () => ( this._default_debounce_ms));
|
|
2886
3212
|
const due = Date.now() + delay;
|
|
2887
3213
|
if (this._timer) {
|
|
2888
3214
|
if (due >= this._due) return;
|
|
@@ -3039,7 +3365,7 @@ var Act = (_class7 = class {
|
|
|
3039
3365
|
// Lanes to arm per event; `"all"` when a dynamic resolver hides the lane.
|
|
3040
3366
|
|
|
3041
3367
|
|
|
3042
|
-
__init27() {this._logger =
|
|
3368
|
+
__init27() {this._logger = _chunkLUHPSF3Ccjs.log.call(void 0, )}
|
|
3043
3369
|
// This Act's ports: its own bag, or the singleton adapters.
|
|
3044
3370
|
|
|
3045
3371
|
// Runs a body so internal `store()`/`cache()` calls resolve to `_ports`.
|
|
@@ -3061,9 +3387,10 @@ var Act = (_class7 = class {
|
|
|
3061
3387
|
this._lanes = lanes;
|
|
3062
3388
|
this._declared_lanes = ["default", ...lanes.map((l) => l.name)];
|
|
3063
3389
|
validate_only_lanes(options.onlyLanes, this._declared_lanes);
|
|
3064
|
-
|
|
3390
|
+
if (options.scoped) _chunkLUHPSF3Ccjs.check_store.call(void 0, options.scoped.store);
|
|
3391
|
+
this._ports = _nullishCoalesce(options.scoped, () => ( _chunkLUHPSF3Ccjs.default_scope.call(void 0, )));
|
|
3065
3392
|
const ports = this._ports;
|
|
3066
|
-
this._scoped =
|
|
3393
|
+
this._scoped = _chunkLUHPSF3Ccjs.make_run_scoped.call(void 0, {
|
|
3067
3394
|
// Getters, not a spread: the singletons resolve lazily, so a later
|
|
3068
3395
|
// `store(...)` / `cache(...)` still takes effect.
|
|
3069
3396
|
get store() {
|
|
@@ -3073,14 +3400,14 @@ var Act = (_class7 = class {
|
|
|
3073
3400
|
return ports.cache;
|
|
3074
3401
|
},
|
|
3075
3402
|
// Parsed per build, so a bad window throws on every build.
|
|
3076
|
-
autoclose_window:
|
|
3403
|
+
autoclose_window: _chunkLUHPSF3Ccjs.resolveAutocloseConfig.call(void 0, options).autocloseWindow
|
|
3077
3404
|
});
|
|
3078
3405
|
this._correlator = _nullishCoalesce(options.correlator, () => ( default_correlator));
|
|
3079
3406
|
this._es = build_es(this._logger, this._correlator, patch_fn);
|
|
3080
3407
|
this._cd = build_drain(this._logger);
|
|
3081
3408
|
const handle = build_handle({
|
|
3082
3409
|
logger: this._logger,
|
|
3083
|
-
reaction_scope:
|
|
3410
|
+
reaction_scope: _chunkLUHPSF3Ccjs.make_reaction_scope.call(void 0, {
|
|
3084
3411
|
do: this.do.bind(this),
|
|
3085
3412
|
load: this.load.bind(this),
|
|
3086
3413
|
query: this.query.bind(this),
|
|
@@ -3110,12 +3437,12 @@ var Act = (_class7 = class {
|
|
|
3110
3437
|
this._ports.store,
|
|
3111
3438
|
options.listen !== false
|
|
3112
3439
|
);
|
|
3113
|
-
|
|
3440
|
+
_chunkLUHPSF3Ccjs.register_weak_disposer.call(void 0, new WeakRef(this), (self) => self.shutdown());
|
|
3114
3441
|
}
|
|
3115
3442
|
// Shared by drain, settle and autoclose; bad knobs throw at build.
|
|
3116
3443
|
_build_breaker(options) {
|
|
3117
3444
|
return new CircuitBreaker(
|
|
3118
|
-
|
|
3445
|
+
_chunkLUHPSF3Ccjs.resolveCircuitBreakerConfig.call(void 0, options.circuitBreaker),
|
|
3119
3446
|
{
|
|
3120
3447
|
on_error: (error, circuit) => this._emit_error(error, circuit),
|
|
3121
3448
|
// When the cooldown elapses, settle once: its scan or claim is the
|
|
@@ -3127,7 +3454,7 @@ var Act = (_class7 = class {
|
|
|
3127
3454
|
// Apps that declare no lanes pass no lane filter to `claim`.
|
|
3128
3455
|
_build_drain_controllers(options, lanes, handle, handle_batch) {
|
|
3129
3456
|
const all_lanes = this._declared_lanes;
|
|
3130
|
-
const only_set = _optionalChain([options, 'access',
|
|
3457
|
+
const only_set = _optionalChain([options, 'access', _153 => _153.onlyLanes, 'optionalAccess', _154 => _154.length]) ? new Set(options.onlyLanes) : void 0;
|
|
3131
3458
|
const active_lanes = only_set ? all_lanes.filter((n) => only_set.has(n)) : all_lanes;
|
|
3132
3459
|
const single_default_lane = lanes.length === 0;
|
|
3133
3460
|
const controllers = /* @__PURE__ */ new Map();
|
|
@@ -3149,7 +3476,7 @@ var Act = (_class7 = class {
|
|
|
3149
3476
|
try {
|
|
3150
3477
|
await this._run_close(targets);
|
|
3151
3478
|
} catch (error) {
|
|
3152
|
-
if (error instanceof
|
|
3479
|
+
if (error instanceof _chunkYFFWCVXWcjs.StoreError) throw error;
|
|
3153
3480
|
this._logger.error(
|
|
3154
3481
|
error,
|
|
3155
3482
|
`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 +3491,7 @@ var Act = (_class7 = class {
|
|
|
3164
3491
|
leaseMillis: cfg.leaseMillis
|
|
3165
3492
|
}
|
|
3166
3493
|
});
|
|
3167
|
-
if (_optionalChain([cfg, 'optionalAccess',
|
|
3494
|
+
if (_optionalChain([cfg, 'optionalAccess', _155 => _155.cycleMs]) !== void 0 && this._drain)
|
|
3168
3495
|
controller.start(cfg.cycleMs);
|
|
3169
3496
|
controllers.set(name, controller);
|
|
3170
3497
|
}
|
|
@@ -3183,7 +3510,7 @@ var Act = (_class7 = class {
|
|
|
3183
3510
|
// Audit deps, built after the controllers so the lane set is final.
|
|
3184
3511
|
_build_audit_deps() {
|
|
3185
3512
|
return {
|
|
3186
|
-
store:
|
|
3513
|
+
store: _chunkLUHPSF3Ccjs.store,
|
|
3187
3514
|
event_to_state: this._event_to_state,
|
|
3188
3515
|
// Declared lanes, not this process's controllers: a lane another
|
|
3189
3516
|
// worker drains is not `unknown-lane`.
|
|
@@ -3196,7 +3523,7 @@ var Act = (_class7 = class {
|
|
|
3196
3523
|
registry: this.registry,
|
|
3197
3524
|
static_targets: classification.static_targets,
|
|
3198
3525
|
cd: this._cd,
|
|
3199
|
-
max_subscribed_streams: _nullishCoalesce(options.maxSubscribedStreams, () => (
|
|
3526
|
+
max_subscribed_streams: _nullishCoalesce(options.maxSubscribedStreams, () => ( _chunkYFFWCVXWcjs.DEFAULT_MAX_SUBSCRIBED_STREAMS)),
|
|
3200
3527
|
// Declared lanes (not active ones): a lane another process claims is
|
|
3201
3528
|
// still a valid destination.
|
|
3202
3529
|
declared_lanes: new Set(this._declared_lanes),
|
|
@@ -3212,10 +3539,10 @@ var Act = (_class7 = class {
|
|
|
3212
3539
|
// Cold start: an idle deferred stream still fires on time after a restart.
|
|
3213
3540
|
async _seed_persisted_defers() {
|
|
3214
3541
|
const now = Date.now();
|
|
3215
|
-
await walk_streams(
|
|
3542
|
+
await walk_streams(_chunkLUHPSF3Ccjs.store.call(void 0, ), (pos) => {
|
|
3216
3543
|
if (pos.deferred_at === void 0 || pos.deferred_at <= now) return;
|
|
3217
3544
|
const controller = this._drain_controllers.get(_nullishCoalesce(pos.lane, () => ( "default")));
|
|
3218
|
-
_optionalChain([controller, 'optionalAccess',
|
|
3545
|
+
_optionalChain([controller, 'optionalAccess', _156 => _156.seed_defer, 'call', _157 => _157(pos.stream, pos.deferred_at)]);
|
|
3219
3546
|
});
|
|
3220
3547
|
}
|
|
3221
3548
|
_build_settle(options) {
|
|
@@ -3228,7 +3555,7 @@ var Act = (_class7 = class {
|
|
|
3228
3555
|
on_settled: (drain) => this.emit("settled", drain),
|
|
3229
3556
|
breaker: this._breaker
|
|
3230
3557
|
},
|
|
3231
|
-
_nullishCoalesce(options.settleDebounceMs, () => (
|
|
3558
|
+
_nullishCoalesce(options.settleDebounceMs, () => ( _chunkYFFWCVXWcjs.DEFAULT_SETTLE_DEBOUNCE_MS))
|
|
3232
3559
|
);
|
|
3233
3560
|
}
|
|
3234
3561
|
|
|
@@ -3248,7 +3575,7 @@ var Act = (_class7 = class {
|
|
|
3248
3575
|
*/
|
|
3249
3576
|
shutdown(options) {
|
|
3250
3577
|
if (!this._shutdown_promise) {
|
|
3251
|
-
|
|
3578
|
+
_chunkLUHPSF3Ccjs.resolveShutdownConfig.call(void 0, options);
|
|
3252
3579
|
this._shutdown_promise = (async () => {
|
|
3253
3580
|
this.stop_correlations();
|
|
3254
3581
|
this._settle.stop(true);
|
|
@@ -3256,7 +3583,7 @@ var Act = (_class7 = class {
|
|
|
3256
3583
|
for (const c of this._drain_controllers.values()) c.stop();
|
|
3257
3584
|
const disposer = await this._notify_disposer;
|
|
3258
3585
|
if (disposer) await disposer();
|
|
3259
|
-
await this._await_inflight(_optionalChain([options, 'optionalAccess',
|
|
3586
|
+
await this._await_inflight(_optionalChain([options, 'optionalAccess', _158 => _158.graceMs]));
|
|
3260
3587
|
await this._scoped(() => this._correlate.release_correlation());
|
|
3261
3588
|
this._emitter.removeAllListeners();
|
|
3262
3589
|
})();
|
|
@@ -3266,10 +3593,10 @@ var Act = (_class7 = class {
|
|
|
3266
3593
|
// The largest `leaseMillis` among lanes with a cycle in flight (the
|
|
3267
3594
|
// default for none or 0, and for a running settle), capped.
|
|
3268
3595
|
_derive_grace_ms(running, settling) {
|
|
3269
|
-
let max = settling ?
|
|
3596
|
+
let max = settling ? _chunkLUHPSF3Ccjs.DEFAULT_LEASE_MILLIS : 0;
|
|
3270
3597
|
for (const c of running)
|
|
3271
|
-
max = Math.max(max, c.lease_millis ||
|
|
3272
|
-
return Math.min(max,
|
|
3598
|
+
max = Math.max(max, c.lease_millis || _chunkLUHPSF3Ccjs.DEFAULT_LEASE_MILLIS);
|
|
3599
|
+
return Math.min(max, _chunkLUHPSF3Ccjs.MAX_SHUTDOWN_GRACE_MS);
|
|
3273
3600
|
}
|
|
3274
3601
|
async _await_inflight(grace_ms) {
|
|
3275
3602
|
const running = [...this._drain_controllers.values()].filter(
|
|
@@ -3316,7 +3643,7 @@ var Act = (_class7 = class {
|
|
|
3316
3643
|
* Executes an action: validates the payload, loads the state, checks its
|
|
3317
3644
|
* preconditions, runs the handler, folds the events it emits, checks the
|
|
3318
3645
|
* state's invariants (its schema) on the result, and commits them with
|
|
3319
|
-
* optimistic concurrency on
|
|
3646
|
+
* optimistic concurrency on every stream it appends to. The reactions to those events
|
|
3320
3647
|
* settle on their own (unless `autoSettle: false`).
|
|
3321
3648
|
*
|
|
3322
3649
|
* @template TKey - Action name from registered actions
|
|
@@ -3326,7 +3653,8 @@ var Act = (_class7 = class {
|
|
|
3326
3653
|
* @param options - Per-call dispatch options ({@link DoOptions}) —
|
|
3327
3654
|
* `reactingTo` to thread correlation, `correlator` to override the
|
|
3328
3655
|
* framework or orchestrator-level correlator for this call only.
|
|
3329
|
-
* @returns
|
|
3656
|
+
* @returns The snapshots of the action's own stream, one per event appended
|
|
3657
|
+
* to it; the loaded snapshot alone when the action commits nothing
|
|
3330
3658
|
*
|
|
3331
3659
|
* @throws {ValidationError} If the payload doesn't match the action schema,
|
|
3332
3660
|
* or the state the action leaves breaks the state schema
|
|
@@ -3352,8 +3680,8 @@ var Act = (_class7 = class {
|
|
|
3352
3680
|
* @see {@link ValidationError}, {@link PreconditionError}, {@link ConcurrencyError}
|
|
3353
3681
|
*/
|
|
3354
3682
|
async do(action2, target, payload, options) {
|
|
3355
|
-
const reacting_to = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
3356
|
-
const do_options = reacting_to === _optionalChain([options, 'optionalAccess',
|
|
3683
|
+
const reacting_to = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _159 => _159.reactingTo]), () => ( _chunkLUHPSF3Ccjs.current_reacting.call(void 0, )));
|
|
3684
|
+
const do_options = reacting_to === _optionalChain([options, 'optionalAccess', _160 => _160.reactingTo]) ? options : { ...options, reactingTo: reacting_to };
|
|
3357
3685
|
return this._scoped(async () => {
|
|
3358
3686
|
const snapshots = await this._es.action(
|
|
3359
3687
|
this.registry.actions[action2],
|
|
@@ -3363,13 +3691,22 @@ var Act = (_class7 = class {
|
|
|
3363
3691
|
do_options
|
|
3364
3692
|
);
|
|
3365
3693
|
if (!snapshots[0].patch) return snapshots;
|
|
3694
|
+
const me = this.registry.actions[action2];
|
|
3366
3695
|
this._wake(snapshots.map((s) => s.event.name));
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3696
|
+
const by_stream = /* @__PURE__ */ new Map();
|
|
3697
|
+
for (const s of snapshots) {
|
|
3698
|
+
const of_stream = by_stream.get(s.event.stream);
|
|
3699
|
+
if (of_stream) of_stream.push(s);
|
|
3700
|
+
else by_stream.set(s.event.stream, [s]);
|
|
3701
|
+
}
|
|
3702
|
+
for (const [stream, of_stream] of by_stream) {
|
|
3703
|
+
const owner = stream === target.stream ? me : me.loads[action2].find(
|
|
3704
|
+
(l) => l.events.includes(of_stream[0].event.name)
|
|
3705
|
+
).state;
|
|
3706
|
+
this.emit("committed", of_stream);
|
|
3707
|
+
this._notify(`committed:${owner.name}`, of_stream);
|
|
3708
|
+
}
|
|
3709
|
+
return snapshots.filter((s) => s.event.stream === target.stream);
|
|
3373
3710
|
});
|
|
3374
3711
|
}
|
|
3375
3712
|
async load(stateOrName, streamOrTarget, callback, asOf) {
|
|
@@ -3418,11 +3755,11 @@ var Act = (_class7 = class {
|
|
|
3418
3755
|
return this._scoped(async () => {
|
|
3419
3756
|
let first;
|
|
3420
3757
|
let last;
|
|
3421
|
-
const count = await
|
|
3758
|
+
const count = await _chunkLUHPSF3Ccjs.store.call(void 0, ).query((e) => {
|
|
3422
3759
|
const gated = this.registry.query_gate(e.name)(e);
|
|
3423
3760
|
if (!first) first = gated;
|
|
3424
3761
|
last = gated;
|
|
3425
|
-
_optionalChain([callback, 'optionalCall',
|
|
3762
|
+
_optionalChain([callback, 'optionalCall', _161 => _161(gated)]);
|
|
3426
3763
|
}, query);
|
|
3427
3764
|
return { first, last, count };
|
|
3428
3765
|
});
|
|
@@ -3448,7 +3785,7 @@ var Act = (_class7 = class {
|
|
|
3448
3785
|
async query_array(query) {
|
|
3449
3786
|
return this._scoped(async () => {
|
|
3450
3787
|
const events = [];
|
|
3451
|
-
await
|
|
3788
|
+
await _chunkLUHPSF3Ccjs.store.call(void 0, ).query((e) => {
|
|
3452
3789
|
events.push(this.registry.query_gate(e.name)(e));
|
|
3453
3790
|
}, query);
|
|
3454
3791
|
return events;
|
|
@@ -3468,14 +3805,14 @@ var Act = (_class7 = class {
|
|
|
3468
3805
|
*/
|
|
3469
3806
|
async forget(stream) {
|
|
3470
3807
|
return this._scoped(async () => {
|
|
3471
|
-
const s =
|
|
3808
|
+
const s = _chunkLUHPSF3Ccjs.store.call(void 0, );
|
|
3472
3809
|
if (!s.forget_pii) {
|
|
3473
3810
|
throw new Error(
|
|
3474
3811
|
`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
3812
|
);
|
|
3476
3813
|
}
|
|
3477
3814
|
const eventCount = await s.forget_pii(stream);
|
|
3478
|
-
await
|
|
3815
|
+
await _chunkLUHPSF3Ccjs.cache.call(void 0, ).invalidate(stream);
|
|
3479
3816
|
if (eventCount > 0) {
|
|
3480
3817
|
this.emit("forgotten", { stream, at: /* @__PURE__ */ new Date(), eventCount });
|
|
3481
3818
|
}
|
|
@@ -3509,7 +3846,7 @@ var Act = (_class7 = class {
|
|
|
3509
3846
|
* @see {@link correlate} for dynamic stream discovery
|
|
3510
3847
|
*/
|
|
3511
3848
|
async drain(options = {}) {
|
|
3512
|
-
|
|
3849
|
+
_chunkLUHPSF3Ccjs.resolveDrainConfig.call(void 0, options);
|
|
3513
3850
|
if (!this._drain)
|
|
3514
3851
|
return { fetched: [], leased: [], acked: [], blocked: [] };
|
|
3515
3852
|
return this._scoped(() => this._drain_all(options));
|
|
@@ -3547,7 +3884,7 @@ var Act = (_class7 = class {
|
|
|
3547
3884
|
}
|
|
3548
3885
|
if (to_arm.size === 0) return false;
|
|
3549
3886
|
this._correlate.arm();
|
|
3550
|
-
for (const lane of to_arm) _optionalChain([this, 'access',
|
|
3887
|
+
for (const lane of to_arm) _optionalChain([this, 'access', _162 => _162._drain_controllers, 'access', _163 => _163.get, 'call', _164 => _164(lane), 'optionalAccess', _165 => _165.arm, 'call', _166 => _166()]);
|
|
3551
3888
|
return true;
|
|
3552
3889
|
}
|
|
3553
3890
|
// In parallel, so a slow lane never holds up a fast one.
|
|
@@ -3689,9 +4026,9 @@ var Act = (_class7 = class {
|
|
|
3689
4026
|
*/
|
|
3690
4027
|
async reset(input) {
|
|
3691
4028
|
return this._scoped(async () => {
|
|
3692
|
-
const count = await
|
|
4029
|
+
const count = await _chunkLUHPSF3Ccjs.store.call(void 0, ).reset(input);
|
|
3693
4030
|
for (const handler of this._batch_handlers.values())
|
|
3694
|
-
_optionalChain([handler, 'access',
|
|
4031
|
+
_optionalChain([handler, 'access', _167 => _167[FOLD_RESET], 'optionalCall', _168 => _168()]);
|
|
3695
4032
|
if (count > 0) {
|
|
3696
4033
|
this._wake();
|
|
3697
4034
|
}
|
|
@@ -3725,7 +4062,7 @@ var Act = (_class7 = class {
|
|
|
3725
4062
|
*/
|
|
3726
4063
|
async unblock(input) {
|
|
3727
4064
|
return this._scoped(async () => {
|
|
3728
|
-
const count = await
|
|
4065
|
+
const count = await _chunkLUHPSF3Ccjs.store.call(void 0, ).unblock(input);
|
|
3729
4066
|
if (count > 0) {
|
|
3730
4067
|
this._wake();
|
|
3731
4068
|
}
|
|
@@ -3780,7 +4117,7 @@ var Act = (_class7 = class {
|
|
|
3780
4117
|
return { ...partial, duration_ms: Date.now() - started };
|
|
3781
4118
|
}
|
|
3782
4119
|
const target = _nullishCoalesce(sink, () => ( (() => {
|
|
3783
|
-
const s =
|
|
4120
|
+
const s = _chunkLUHPSF3Ccjs.store.call(void 0, );
|
|
3784
4121
|
if (!s.restore) throw new Error("adapter has no restore capability");
|
|
3785
4122
|
return s;
|
|
3786
4123
|
})()));
|
|
@@ -3826,11 +4163,11 @@ var Act = (_class7 = class {
|
|
|
3826
4163
|
async blocked_streams(options) {
|
|
3827
4164
|
return this._scoped(async () => {
|
|
3828
4165
|
const positions = [];
|
|
3829
|
-
await
|
|
4166
|
+
await _chunkLUHPSF3Ccjs.store.call(void 0, ).query_streams(
|
|
3830
4167
|
(p) => {
|
|
3831
4168
|
positions.push(p);
|
|
3832
4169
|
},
|
|
3833
|
-
{ blocked: true, after: _optionalChain([options, 'optionalAccess',
|
|
4170
|
+
{ blocked: true, after: _optionalChain([options, 'optionalAccess', _169 => _169.after]), limit: _optionalChain([options, 'optionalAccess', _170 => _170.limit]) }
|
|
3834
4171
|
);
|
|
3835
4172
|
return positions;
|
|
3836
4173
|
});
|
|
@@ -3878,7 +4215,7 @@ var Act = (_class7 = class {
|
|
|
3878
4215
|
* @see {@link Store.prioritize} for the underlying primitive
|
|
3879
4216
|
*/
|
|
3880
4217
|
async prioritize(filter, priority) {
|
|
3881
|
-
return this._scoped(() =>
|
|
4218
|
+
return this._scoped(() => _chunkLUHPSF3Ccjs.store.call(void 0, ).prioritize(filter, priority));
|
|
3882
4219
|
}
|
|
3883
4220
|
// Shared by `close()` and reaction-requested closes.
|
|
3884
4221
|
async _run_close(targets) {
|
|
@@ -3958,222 +4295,11 @@ var Act = (_class7 = class {
|
|
|
3958
4295
|
* @see {@link correlate} for manual correlation
|
|
3959
4296
|
*/
|
|
3960
4297
|
settle(options) {
|
|
3961
|
-
|
|
4298
|
+
_chunkLUHPSF3Ccjs.resolveSettleConfig.call(void 0, _nullishCoalesce(options, () => ( {})));
|
|
3962
4299
|
this._schedule(options);
|
|
3963
4300
|
}
|
|
3964
4301
|
}, _class7);
|
|
3965
4302
|
|
|
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
4303
|
// src/builders/merge.ts
|
|
4178
4304
|
|
|
4179
4305
|
function base_type_name(zodType) {
|
|
@@ -4273,8 +4399,8 @@ function merge_into_existing(state2, existing, states, actions, events) {
|
|
|
4273
4399
|
actions: { ...existing.actions, ...state2.actions },
|
|
4274
4400
|
patch: merged_patch,
|
|
4275
4401
|
on: { ...existing.on, ...state2.on },
|
|
4276
|
-
given: { ...existing.given, ...state2.given },
|
|
4277
4402
|
requires: { ...existing.requires, ...state2.requires },
|
|
4403
|
+
loads: existing.loads || state2.loads ? { ...existing.loads, ...state2.loads } : void 0,
|
|
4278
4404
|
snap: pick_declared(existing.snap, state2.snap, "snap strategy", state2.name),
|
|
4279
4405
|
// Per-action retry policy is keyed by action name, so the two partials'
|
|
4280
4406
|
// maps combine. Left `undefined` when neither declared one, so the
|
|
@@ -4367,9 +4493,9 @@ var _this_ = ({ stream }) => ({
|
|
|
4367
4493
|
|
|
4368
4494
|
// src/builders/builder-utils.ts
|
|
4369
4495
|
function register_lane(config2, lanes) {
|
|
4370
|
-
|
|
4371
|
-
if (config2.name ===
|
|
4372
|
-
throw new Error(`Lane "${
|
|
4496
|
+
_chunkLUHPSF3Ccjs.resolveLaneConfig.call(void 0, config2);
|
|
4497
|
+
if (config2.name === _chunkYFFWCVXWcjs.DEFAULT_LANE)
|
|
4498
|
+
throw new Error(`Lane "${_chunkYFFWCVXWcjs.DEFAULT_LANE}" is reserved`);
|
|
4373
4499
|
const existing = lanes.find((l) => l.name === config2.name);
|
|
4374
4500
|
if (!existing) return void lanes.push(config2);
|
|
4375
4501
|
if (existing.leaseMillis !== config2.leaseMillis || existing.streamLimit !== config2.streamLimit || existing.cycleMs !== config2.cycleMs)
|
|
@@ -4411,10 +4537,10 @@ function reaction_on(event, events, builder) {
|
|
|
4411
4537
|
// Validate the whole bag at the declaration site so a bad
|
|
4412
4538
|
// `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,
|
|
4413
4539
|
// not a NaN gate on the first retry.
|
|
4414
|
-
options:
|
|
4415
|
-
blockOnError: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
4416
|
-
maxRetries: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
4417
|
-
backoff: _optionalChain([options, 'optionalAccess',
|
|
4540
|
+
options: _chunkLUHPSF3Ccjs.resolveReactionConfig.call(void 0, {
|
|
4541
|
+
blockOnError: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _171 => _171.blockOnError]), () => ( _chunkLUHPSF3Ccjs.DEFAULT_BLOCK_ON_ERROR)),
|
|
4542
|
+
maxRetries: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _172 => _172.maxRetries]), () => ( _chunkLUHPSF3Ccjs.DEFAULT_MAX_RETRIES)),
|
|
4543
|
+
backoff: _optionalChain([options, 'optionalAccess', _173 => _173.backoff])
|
|
4418
4544
|
})
|
|
4419
4545
|
};
|
|
4420
4546
|
},
|
|
@@ -4433,25 +4559,47 @@ function reaction_on(event, events, builder) {
|
|
|
4433
4559
|
|
|
4434
4560
|
// src/internal/date-reviver.ts
|
|
4435
4561
|
|
|
4436
|
-
function variant_schema(schema) {
|
|
4437
|
-
const shape = _optionalChain([
|
|
4562
|
+
function variant_schema(schema, walk) {
|
|
4563
|
+
const shape = _optionalChain([_chunkYFFWCVXWcjs.def_of.call(void 0, schema), 'optionalAccess', _174 => _174.shape]);
|
|
4438
4564
|
if (!shape) {
|
|
4439
|
-
const dates =
|
|
4565
|
+
const dates = walk(schema);
|
|
4440
4566
|
return { schema: _nullishCoalesce(dates, () => ( schema)), dated: !!dates };
|
|
4441
4567
|
}
|
|
4442
4568
|
const next = {};
|
|
4443
4569
|
let dated = false;
|
|
4444
4570
|
for (const [key, field] of Object.entries(shape)) {
|
|
4445
|
-
const dates =
|
|
4571
|
+
const dates = walk(field);
|
|
4446
4572
|
if (dates) dated = true;
|
|
4447
4573
|
next[key] = (_nullishCoalesce(dates, () => ( field))).optional();
|
|
4448
4574
|
}
|
|
4449
4575
|
return { schema: _zod.z.looseObject(next), dated };
|
|
4450
4576
|
}
|
|
4451
4577
|
function date_reviver_schema(schema) {
|
|
4452
|
-
|
|
4578
|
+
let recursive = false;
|
|
4579
|
+
const pass = (tie) => {
|
|
4580
|
+
const done = /* @__PURE__ */ new Map();
|
|
4581
|
+
const active = /* @__PURE__ */ new Set();
|
|
4582
|
+
const walk = (node) => {
|
|
4583
|
+
if (done.has(node)) return done.get(node);
|
|
4584
|
+
if (active.has(node)) {
|
|
4585
|
+
recursive = true;
|
|
4586
|
+
return tie ? _zod.z.lazy(() => done.get(node)) : void 0;
|
|
4587
|
+
}
|
|
4588
|
+
active.add(node);
|
|
4589
|
+
const result = build(node, walk);
|
|
4590
|
+
active.delete(node);
|
|
4591
|
+
done.set(node, result);
|
|
4592
|
+
return result;
|
|
4593
|
+
};
|
|
4594
|
+
return walk(schema);
|
|
4595
|
+
};
|
|
4596
|
+
const first = pass(false);
|
|
4597
|
+
return first && recursive ? pass(true) : first;
|
|
4598
|
+
}
|
|
4599
|
+
function build(schema, walk) {
|
|
4600
|
+
const def = _chunkYFFWCVXWcjs.def_of.call(void 0, schema);
|
|
4453
4601
|
if (!def) return void 0;
|
|
4454
|
-
const inner = () =>
|
|
4602
|
+
const inner = () => walk(def.innerType);
|
|
4455
4603
|
switch (def.type) {
|
|
4456
4604
|
case "date":
|
|
4457
4605
|
return _zod.z.coerce.date();
|
|
@@ -4460,39 +4608,48 @@ function date_reviver_schema(schema) {
|
|
|
4460
4608
|
if (!shape) return void 0;
|
|
4461
4609
|
const dated = {};
|
|
4462
4610
|
for (const [key, field] of Object.entries(shape)) {
|
|
4463
|
-
const dates =
|
|
4611
|
+
const dates = walk(field);
|
|
4464
4612
|
if (dates) dated[key] = dates.optional();
|
|
4465
4613
|
}
|
|
4466
4614
|
return Object.keys(dated).length ? _zod.z.looseObject(dated) : void 0;
|
|
4467
4615
|
}
|
|
4468
4616
|
case "array": {
|
|
4469
|
-
const element =
|
|
4617
|
+
const element = walk(def.element);
|
|
4470
4618
|
return element && _zod.z.array(element);
|
|
4471
4619
|
}
|
|
4472
4620
|
case "tuple": {
|
|
4473
|
-
const items = def.items.map((i) =>
|
|
4621
|
+
const items = def.items.map((i) => walk(i));
|
|
4474
4622
|
return items.some(Boolean) ? _zod.z.tuple(items.map((i) => _nullishCoalesce(i, () => ( _zod.z.unknown())))) : void 0;
|
|
4475
4623
|
}
|
|
4476
4624
|
case "record": {
|
|
4477
|
-
const value =
|
|
4625
|
+
const value = walk(def.valueType);
|
|
4478
4626
|
return value && _zod.z.record(_zod.z.string(), value);
|
|
4479
4627
|
}
|
|
4480
4628
|
case "union": {
|
|
4481
|
-
const variants = def.options.map(
|
|
4629
|
+
const variants = def.options.map(
|
|
4630
|
+
(o) => variant_schema(o, walk)
|
|
4631
|
+
);
|
|
4482
4632
|
return variants.some((v) => v.dated) ? _zod.z.union(variants.map((v) => v.schema)) : void 0;
|
|
4483
4633
|
}
|
|
4484
4634
|
case "nullable":
|
|
4485
|
-
return _optionalChain([inner, 'call',
|
|
4635
|
+
return _optionalChain([inner, 'call', _175 => _175(), 'optionalAccess', _176 => _176.nullable, 'call', _177 => _177()]);
|
|
4486
4636
|
case "pipe":
|
|
4487
|
-
return
|
|
4637
|
+
return walk(def.out);
|
|
4638
|
+
case "lazy":
|
|
4639
|
+
return walk(def.getter());
|
|
4640
|
+
case "intersection": {
|
|
4641
|
+
const left = walk(def.left);
|
|
4642
|
+
const right = walk(def.right);
|
|
4643
|
+
return left && right ? left.pipe(right) : _nullishCoalesce(left, () => ( right));
|
|
4644
|
+
}
|
|
4488
4645
|
default:
|
|
4489
|
-
return
|
|
4646
|
+
return _chunkYFFWCVXWcjs.inner_of.call(void 0, def) ? inner() : void 0;
|
|
4490
4647
|
}
|
|
4491
4648
|
}
|
|
4492
4649
|
|
|
4493
4650
|
// src/builders/event-builder.ts
|
|
4494
4651
|
function event_tags(schema) {
|
|
4495
|
-
const pii =
|
|
4652
|
+
const pii = _chunkYFFWCVXWcjs.pii_schemas.call(void 0, schema);
|
|
4496
4653
|
const pii_dates = {};
|
|
4497
4654
|
for (const [key, field] of Object.entries(pii)) {
|
|
4498
4655
|
const dates = date_reviver_schema(field);
|
|
@@ -4530,7 +4687,7 @@ function make_event_reader(tags, disclosure, predicate = null) {
|
|
|
4530
4687
|
});
|
|
4531
4688
|
}
|
|
4532
4689
|
function build_events(registry, states, lanes, owners) {
|
|
4533
|
-
const declared = /* @__PURE__ */ new Set([
|
|
4690
|
+
const declared = /* @__PURE__ */ new Set([_chunkYFFWCVXWcjs.DEFAULT_LANE, ...lanes.map((l) => l.name)]);
|
|
4534
4691
|
const lane_errors = [];
|
|
4535
4692
|
const tags = /* @__PURE__ */ new Map();
|
|
4536
4693
|
const sensitive2 = /* @__PURE__ */ new Map();
|
|
@@ -4605,7 +4762,7 @@ function build_events(registry, states, lanes, owners) {
|
|
|
4605
4762
|
if (reader) readers.set(event_name, reader);
|
|
4606
4763
|
}
|
|
4607
4764
|
const snap2 = make_event_reader(event_tags(state2.state), "redact", null);
|
|
4608
|
-
if (snap2) readers.set(
|
|
4765
|
+
if (snap2) readers.set(_chunkYFFWCVXWcjs.SNAP_EVENT, snap2);
|
|
4609
4766
|
if (readers.size === 0) continue;
|
|
4610
4767
|
state2.view = (event, actor) => (_nullishCoalesce(readers.get(event.name), () => ( IDENTITY_GATE)))(event, actor);
|
|
4611
4768
|
}
|
|
@@ -4613,7 +4770,7 @@ function build_events(registry, states, lanes, owners) {
|
|
|
4613
4770
|
return { sensitive: sensitive2, advisory, query_readers, handler_readers };
|
|
4614
4771
|
}
|
|
4615
4772
|
function reads_as_string(schema) {
|
|
4616
|
-
const type = _optionalChain([
|
|
4773
|
+
const type = _optionalChain([_chunkYFFWCVXWcjs.def_of.call(void 0, _chunkYFFWCVXWcjs.output_of.call(void 0, schema)), 'optionalAccess', _178 => _178.type]);
|
|
4617
4774
|
return type === "string" || type === "transform";
|
|
4618
4775
|
}
|
|
4619
4776
|
|
|
@@ -4671,7 +4828,7 @@ function act() {
|
|
|
4671
4828
|
let _built = false;
|
|
4672
4829
|
const read_wrap = (original) => {
|
|
4673
4830
|
const wrapped = async (events, stream) => {
|
|
4674
|
-
const read = events.map((e) => _nullishCoalesce(_optionalChain([_hr, 'access',
|
|
4831
|
+
const read = events.map((e) => _nullishCoalesce(_optionalChain([_hr, 'access', _179 => _179.get, 'call', _180 => _180(e.name), 'optionalCall', _181 => _181(e)]), () => ( e)));
|
|
4675
4832
|
return original(read, stream);
|
|
4676
4833
|
};
|
|
4677
4834
|
const reset = original[FOLD_RESET];
|
|
@@ -4712,7 +4869,7 @@ function act() {
|
|
|
4712
4869
|
});
|
|
4713
4870
|
}
|
|
4714
4871
|
for (const [action_name, handler] of Object.entries(state2.on)) {
|
|
4715
|
-
const static_target = _optionalChain([handler, 'optionalAccess',
|
|
4872
|
+
const static_target = _optionalChain([handler, 'optionalAccess', _182 => _182._static_emit]);
|
|
4716
4873
|
if (static_target && deprecated.has(static_target)) {
|
|
4717
4874
|
const current = current_version_of(static_target, event_names);
|
|
4718
4875
|
throw new Error(
|
|
@@ -4725,7 +4882,7 @@ function act() {
|
|
|
4725
4882
|
const list = deprecation_summary.map(
|
|
4726
4883
|
(d) => `"${d.deprecated}" (current: "${d.current}", state: "${d.state_name}")`
|
|
4727
4884
|
).join(", ");
|
|
4728
|
-
|
|
4885
|
+
_chunkLUHPSF3Ccjs.log.call(void 0, ).info(
|
|
4729
4886
|
`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
4887
|
);
|
|
4731
4888
|
}
|
|
@@ -4767,7 +4924,7 @@ function act() {
|
|
|
4767
4924
|
return reaction_on(event, registry.events, builder);
|
|
4768
4925
|
},
|
|
4769
4926
|
build: (options) => {
|
|
4770
|
-
|
|
4927
|
+
_chunkLUHPSF3Ccjs.resolveActConfig.call(void 0, options);
|
|
4771
4928
|
if (!_built) {
|
|
4772
4929
|
for (const proj of pending_projections) add_projection(proj);
|
|
4773
4930
|
for (const proj of fold_projections) {
|
|
@@ -4785,7 +4942,7 @@ function act() {
|
|
|
4785
4942
|
`State projection "${proj.target}" of "${fold.name}" is missing events ${missing.join(", ")} \u2014 pass every partial of the state to .of()`
|
|
4786
4943
|
);
|
|
4787
4944
|
const claimed = fold_specs.find((s) => s.target === proj.target);
|
|
4788
|
-
if (_optionalChain([claimed, 'optionalAccess',
|
|
4945
|
+
if (_optionalChain([claimed, 'optionalAccess', _183 => _183.projection]) === proj) continue;
|
|
4789
4946
|
if (batch_handlers.has(proj.target) || claimed)
|
|
4790
4947
|
throw new Error(
|
|
4791
4948
|
`Duplicate projection target "${proj.target}" \u2014 a target is served by one batch handler or one state projection, never both`
|
|
@@ -4807,7 +4964,39 @@ function act() {
|
|
|
4807
4964
|
for (const [name, gate] of built.query_readers) _qg.set(name, gate);
|
|
4808
4965
|
for (const [name, gate] of built.handler_readers) _hr.set(name, gate);
|
|
4809
4966
|
finalize_deprecations();
|
|
4810
|
-
if (built.advisory)
|
|
4967
|
+
if (built.advisory) _chunkLUHPSF3Ccjs.log.call(void 0, ).warn(built.advisory);
|
|
4968
|
+
for (const [name, state2] of states) {
|
|
4969
|
+
if (!state2.loads) continue;
|
|
4970
|
+
const resolved = {};
|
|
4971
|
+
for (const [action2, loads] of Object.entries(state2.loads)) {
|
|
4972
|
+
resolved[action2] = loads.map((l) => {
|
|
4973
|
+
const registered = states.get(l.state.name);
|
|
4974
|
+
if (!registered)
|
|
4975
|
+
throw new Error(
|
|
4976
|
+
`Action "${action2}" loads "${l.state.name}", which is not registered \u2014 add it via withState/withSlice before build()`
|
|
4977
|
+
);
|
|
4978
|
+
const deprecated = l.events.find(
|
|
4979
|
+
(e) => _optionalChain([_de, 'access', _184 => _184.get, 'call', _185 => _185(registered.name), 'optionalAccess', _186 => _186.has, 'call', _187 => _187(e)])
|
|
4980
|
+
);
|
|
4981
|
+
if (deprecated)
|
|
4982
|
+
throw new Error(
|
|
4983
|
+
`Action "${action2}" lists deprecated event "${deprecated}" on its load of "${registered.name}". A newer version exists: "${current_version_of(deprecated, Object.keys(registered.events))}". List the current version instead.`
|
|
4984
|
+
);
|
|
4985
|
+
return { ...l, state: registered };
|
|
4986
|
+
});
|
|
4987
|
+
}
|
|
4988
|
+
for (const [action2, loads] of Object.entries(resolved)) {
|
|
4989
|
+
const static_target = state2.on[action2]._static_emit;
|
|
4990
|
+
if (static_target && loads.some((l) => l.events.includes(static_target)))
|
|
4991
|
+
throw new Error(
|
|
4992
|
+
`Action "${action2}" statically emits "${static_target}", which its load lists, so nothing goes to its own stream; emit one of its own events too`
|
|
4993
|
+
);
|
|
4994
|
+
}
|
|
4995
|
+
const own = { ...state2, loads: resolved };
|
|
4996
|
+
states.set(name, own);
|
|
4997
|
+
for (const action2 of Object.keys(own.actions))
|
|
4998
|
+
registry.actions[action2] = own;
|
|
4999
|
+
}
|
|
4811
5000
|
for (const state2 of states.values()) {
|
|
4812
5001
|
if (state2.disclose) _dp.set(state2.name, state2.disclose);
|
|
4813
5002
|
if (state2.autoclose) _ac.set(state2.name, state2.autoclose);
|
|
@@ -4819,7 +5008,7 @@ function act() {
|
|
|
4819
5008
|
synthesize_autoclose_reactions(
|
|
4820
5009
|
registry,
|
|
4821
5010
|
states,
|
|
4822
|
-
|
|
5011
|
+
_chunkLUHPSF3Ccjs.current_autoclose_window
|
|
4823
5012
|
);
|
|
4824
5013
|
Object.freeze(registry.actions);
|
|
4825
5014
|
Object.freeze(registry.events);
|
|
@@ -4867,8 +5056,8 @@ function _projection(target) {
|
|
|
4867
5056
|
handler,
|
|
4868
5057
|
resolver: _nullishCoalesce(default_resolver, () => ( _this_)),
|
|
4869
5058
|
options: {
|
|
4870
|
-
blockOnError:
|
|
4871
|
-
maxRetries:
|
|
5059
|
+
blockOnError: _chunkLUHPSF3Ccjs.DEFAULT_BLOCK_ON_ERROR,
|
|
5060
|
+
maxRetries: _chunkLUHPSF3Ccjs.DEFAULT_MAX_RETRIES
|
|
4872
5061
|
}
|
|
4873
5062
|
}),
|
|
4874
5063
|
widened
|
|
@@ -4909,7 +5098,7 @@ function _projection(target) {
|
|
|
4909
5098
|
throw new Error(
|
|
4910
5099
|
`Projection "${target}" .of() partials must share one state name \u2014 got "${name}" and "${partial.name}"`
|
|
4911
5100
|
);
|
|
4912
|
-
const config2 =
|
|
5101
|
+
const config2 = _chunkLUHPSF3Ccjs.resolveFoldConfig.call(void 0, options);
|
|
4913
5102
|
const fold_events = {};
|
|
4914
5103
|
for (const partial of partials)
|
|
4915
5104
|
for (const [event_name, schema] of Object.entries(partial.events)) {
|
|
@@ -4927,8 +5116,8 @@ function _projection(target) {
|
|
|
4927
5116
|
handler: noop,
|
|
4928
5117
|
resolver: { target },
|
|
4929
5118
|
options: {
|
|
4930
|
-
blockOnError:
|
|
4931
|
-
maxRetries:
|
|
5119
|
+
blockOnError: _chunkLUHPSF3Ccjs.DEFAULT_BLOCK_ON_ERROR,
|
|
5120
|
+
maxRetries: _chunkLUHPSF3Ccjs.DEFAULT_MAX_RETRIES
|
|
4932
5121
|
}
|
|
4933
5122
|
}
|
|
4934
5123
|
]
|
|
@@ -5044,13 +5233,29 @@ function action_builder(state2) {
|
|
|
5044
5233
|
throw new Error(`Duplicate action "${action2}"`);
|
|
5045
5234
|
internal.actions[action2] = schema;
|
|
5046
5235
|
if (options) {
|
|
5047
|
-
|
|
5236
|
+
_chunkLUHPSF3Ccjs.resolveActionConfig.call(void 0, options);
|
|
5048
5237
|
internal.options ??= {};
|
|
5049
5238
|
internal.options[action2] = options;
|
|
5050
5239
|
}
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5240
|
+
const loads = [];
|
|
5241
|
+
function load2(state3, target, events = [], name = state3.name) {
|
|
5242
|
+
if (loads.some((l) => l.name === name))
|
|
5243
|
+
throw new Error(
|
|
5244
|
+
`Action "${action2}" loads "${name}" twice; name each load of the same state`
|
|
5245
|
+
);
|
|
5246
|
+
for (const event of events) {
|
|
5247
|
+
if (!(event in state3.events))
|
|
5248
|
+
throw new Error(
|
|
5249
|
+
`Action "${action2}" lists "${event}" on its load of "${state3.name}", which doesn't emit it`
|
|
5250
|
+
);
|
|
5251
|
+
if (loads.some((l) => l.events.includes(event)))
|
|
5252
|
+
throw new Error(
|
|
5253
|
+
`Action "${action2}" lists "${event}" on two loads; an event goes to one stream`
|
|
5254
|
+
);
|
|
5255
|
+
}
|
|
5256
|
+
loads.push({ state: state3, target, events, name });
|
|
5257
|
+
(internal.loads ??= {})[action2] = loads;
|
|
5258
|
+
return { loads: load2, requires, emit };
|
|
5054
5259
|
}
|
|
5055
5260
|
function requires(rules) {
|
|
5056
5261
|
(internal.requires ??= {})[action2] = rules;
|
|
@@ -5071,7 +5276,7 @@ function action_builder(state2) {
|
|
|
5071
5276
|
}
|
|
5072
5277
|
return builder;
|
|
5073
5278
|
}
|
|
5074
|
-
return {
|
|
5279
|
+
return { loads: load2, requires, emit };
|
|
5075
5280
|
},
|
|
5076
5281
|
snap(snap2) {
|
|
5077
5282
|
internal.snap = snap2;
|
|
@@ -5338,5 +5543,7 @@ function write_line(writer, line) {
|
|
|
5338
5543
|
|
|
5339
5544
|
|
|
5340
5545
|
|
|
5341
|
-
|
|
5546
|
+
|
|
5547
|
+
|
|
5548
|
+
exports.Act = Act; exports.ActorSchema = _chunkYFFWCVXWcjs.ActorSchema; exports.CausationEventSchema = _chunkYFFWCVXWcjs.CausationEventSchema; exports.CommittedMetaSchema = _chunkYFFWCVXWcjs.CommittedMetaSchema; exports.ConcurrencyError = _chunkYFFWCVXWcjs.ConcurrencyError; exports.ConsoleLogger = _chunkLUHPSF3Ccjs.ConsoleLogger; exports.CsvFile = CsvFile; exports.DEFAULT_LANE = _chunkYFFWCVXWcjs.DEFAULT_LANE; exports.DEFAULT_MAX_SUBSCRIBED_STREAMS = _chunkYFFWCVXWcjs.DEFAULT_MAX_SUBSCRIBED_STREAMS; exports.DEFAULT_QUERY_STREAMS_LIMIT = _chunkLUHPSF3Ccjs.DEFAULT_QUERY_STREAMS_LIMIT; exports.DEFAULT_SETTLE_DEBOUNCE_MS = _chunkYFFWCVXWcjs.DEFAULT_SETTLE_DEBOUNCE_MS; exports.DeferSignal = _chunkYFFWCVXWcjs.DeferSignal; exports.Environments = _chunkYFFWCVXWcjs.Environments; exports.Errors = _chunkYFFWCVXWcjs.Errors; exports.EventMetaSchema = _chunkYFFWCVXWcjs.EventMetaSchema; exports.ExitCodes = _chunkYFFWCVXWcjs.ExitCodes; exports.InMemoryCache = _chunkLUHPSF3Ccjs.InMemoryCache; exports.InMemoryStore = _chunkLUHPSF3Ccjs.InMemoryStore; exports.LogLevels = _chunkYFFWCVXWcjs.LogLevels; exports.NonRetryableError = _chunkYFFWCVXWcjs.NonRetryableError; exports.PackageSchema = _chunkLUHPSF3Ccjs.PackageSchema; exports.PreconditionError = _chunkYFFWCVXWcjs.PreconditionError; exports.QuerySchema = _chunkYFFWCVXWcjs.QuerySchema; exports.REDACTED = _chunkYFFWCVXWcjs.REDACTED; exports.SHREDDED = _chunkYFFWCVXWcjs.SHREDDED; exports.SNAP_EVENT = _chunkYFFWCVXWcjs.SNAP_EVENT; exports.StoreError = _chunkYFFWCVXWcjs.StoreError; exports.StreamClosedError = _chunkYFFWCVXWcjs.StreamClosedError; exports.TOMBSTONE_EVENT = _chunkYFFWCVXWcjs.TOMBSTONE_EVENT; exports.TargetSchema = _chunkYFFWCVXWcjs.TargetSchema; exports.ValidationError = _chunkYFFWCVXWcjs.ValidationError; exports.ZodEmpty = _chunkYFFWCVXWcjs.ZodEmpty; exports.act = act; exports.cache = _chunkLUHPSF3Ccjs.cache; exports.check_appends = _chunkLUHPSF3Ccjs.check_appends; exports.config = _chunkLUHPSF3Ccjs.config; exports.dateReviver = _chunkLUHPSF3Ccjs.dateReviver; exports.default_scope = _chunkLUHPSF3Ccjs.default_scope; exports.dispose = _chunkLUHPSF3Ccjs.dispose; exports.disposeAndExit = _chunkLUHPSF3Ccjs.disposeAndExit; exports.extend = _chunkLUHPSF3Ccjs.extend; exports.fair_slots = _chunkLUHPSF3Ccjs.fair_slots; exports.is_literal_source = _chunkLUHPSF3Ccjs.is_literal_source; exports.log = _chunkLUHPSF3Ccjs.log; exports.pii_fields = _chunkYFFWCVXWcjs.pii_fields; exports.port = _chunkLUHPSF3Ccjs.port; exports.projection = projection; exports.resolveAutocloseConfig = _chunkLUHPSF3Ccjs.resolveAutocloseConfig2; exports.sensitive = _chunkYFFWCVXWcjs.sensitive; exports.sleep = _chunkLUHPSF3Ccjs.sleep; exports.slice = slice; exports.state = state; exports.store = _chunkLUHPSF3Ccjs.store; exports.validate = _chunkLUHPSF3Ccjs.validate;
|
|
5342
5549
|
//# sourceMappingURL=index.cjs.map
|