@rotorsoft/act 0.32.0 → 0.32.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/@types/act-builder.d.ts.map +1 -1
  3. package/dist/@types/act.d.ts +10 -10
  4. package/dist/@types/act.d.ts.map +1 -1
  5. package/dist/@types/adapters/InMemoryStore.d.ts +2 -4
  6. package/dist/@types/adapters/InMemoryStore.d.ts.map +1 -1
  7. package/dist/@types/internal/drain.d.ts +39 -0
  8. package/dist/@types/internal/drain.d.ts.map +1 -0
  9. package/dist/@types/{event-sourcing.d.ts → internal/event-sourcing.d.ts} +15 -2
  10. package/dist/@types/internal/event-sourcing.d.ts.map +1 -0
  11. package/dist/@types/internal/index.d.ts +22 -0
  12. package/dist/@types/internal/index.d.ts.map +1 -0
  13. package/dist/@types/internal/merge.d.ts +19 -0
  14. package/dist/@types/internal/merge.d.ts.map +1 -0
  15. package/dist/@types/internal/tracing.d.ts +36 -0
  16. package/dist/@types/internal/tracing.d.ts.map +1 -0
  17. package/dist/@types/ports.d.ts +1 -25
  18. package/dist/@types/ports.d.ts.map +1 -1
  19. package/dist/@types/projection-builder.d.ts.map +1 -1
  20. package/dist/@types/slice-builder.d.ts.map +1 -1
  21. package/dist/@types/state-builder.d.ts.map +1 -1
  22. package/dist/@types/types/action.d.ts +13 -0
  23. package/dist/@types/types/action.d.ts.map +1 -1
  24. package/dist/@types/types/ports.d.ts +2 -6
  25. package/dist/@types/types/ports.d.ts.map +1 -1
  26. package/dist/@types/types/reaction.d.ts +9 -3
  27. package/dist/@types/types/reaction.d.ts.map +1 -1
  28. package/dist/index.cjs +291 -252
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.js +291 -251
  31. package/dist/index.js.map +1 -1
  32. package/package.json +1 -1
  33. package/dist/@types/event-sourcing.d.ts.map +0 -1
  34. package/dist/@types/merge.d.ts +0 -43
  35. package/dist/@types/merge.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -648,63 +648,6 @@ function dispose(disposer) {
648
648
  }
649
649
  var SNAP_EVENT = "__snapshot__";
650
650
  var TOMBSTONE_EVENT = "__tombstone__";
651
- function build_tracer(logLevel2) {
652
- if (logLevel2 === "trace") {
653
- const logger4 = log();
654
- return {
655
- fetched: (fetched) => {
656
- const data = Object.fromEntries(
657
- fetched.map(({ stream, source, events }) => {
658
- const key = source ? `${stream}<-${source}` : stream;
659
- const value = Object.fromEntries(
660
- events.map(({ id, stream: stream2, name }) => [id, { [stream2]: name }])
661
- );
662
- return [key, value];
663
- })
664
- );
665
- logger4.trace(data, ">> fetch");
666
- },
667
- correlated: (streams) => {
668
- const data = streams.map(({ stream }) => stream).join(" ");
669
- logger4.trace(`>> correlate ${data}`);
670
- },
671
- leased: (leases) => {
672
- const data = Object.fromEntries(
673
- leases.map(({ stream, at, retry }) => [stream, { at, retry }])
674
- );
675
- logger4.trace(data, ">> lease");
676
- },
677
- acked: (leases) => {
678
- const data = Object.fromEntries(
679
- leases.map(({ stream, at, retry }) => [stream, { at, retry }])
680
- );
681
- logger4.trace(data, ">> ack");
682
- },
683
- blocked: (leases) => {
684
- const data = Object.fromEntries(
685
- leases.map(({ stream, at, retry, error }) => [
686
- stream,
687
- { at, retry, error }
688
- ])
689
- );
690
- logger4.trace(data, ">> block");
691
- }
692
- };
693
- } else {
694
- return {
695
- fetched: () => {
696
- },
697
- correlated: () => {
698
- },
699
- leased: () => {
700
- },
701
- acked: () => {
702
- },
703
- blocked: () => {
704
- }
705
- };
706
- }
707
- }
708
651
 
709
652
  // src/signals.ts
710
653
  var logger = log();
@@ -729,14 +672,162 @@ process.once("unhandledRejection", async (arg) => {
729
672
  import { randomUUID as randomUUID2 } from "crypto";
730
673
  import EventEmitter from "events";
731
674
 
732
- // src/event-sourcing.ts
675
+ // src/internal/merge.ts
676
+ import { ZodObject } from "zod";
677
+ function baseTypeName(zodType) {
678
+ let t = zodType;
679
+ while (typeof t.unwrap === "function") {
680
+ t = t.unwrap();
681
+ }
682
+ return t.constructor.name;
683
+ }
684
+ function mergeSchemas(existing, incoming, stateName) {
685
+ if (existing instanceof ZodObject && incoming instanceof ZodObject) {
686
+ const existingShape = existing.shape;
687
+ const incomingShape = incoming.shape;
688
+ for (const key of Object.keys(incomingShape)) {
689
+ if (key in existingShape) {
690
+ const existingBase = baseTypeName(existingShape[key]);
691
+ const incomingBase = baseTypeName(incomingShape[key]);
692
+ if (existingBase !== incomingBase) {
693
+ throw new Error(
694
+ `Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
695
+ );
696
+ }
697
+ }
698
+ }
699
+ return existing.extend(incomingShape);
700
+ }
701
+ return existing;
702
+ }
703
+ function mergeInits(existing, incoming) {
704
+ return () => ({ ...existing(), ...incoming() });
705
+ }
706
+ function registerState(state2, states, actions, events) {
707
+ const existing = states.get(state2.name);
708
+ if (existing) {
709
+ mergeIntoExisting(state2, existing, states, actions, events);
710
+ } else {
711
+ registerNewState(state2, states, actions, events);
712
+ }
713
+ }
714
+ function registerNewState(state2, states, actions, events) {
715
+ states.set(state2.name, state2);
716
+ for (const name of Object.keys(state2.actions)) {
717
+ if (actions[name]) throw new Error(`Duplicate action "${name}"`);
718
+ actions[name] = state2;
719
+ }
720
+ for (const name of Object.keys(state2.events)) {
721
+ if (events[name]) throw new Error(`Duplicate event "${name}"`);
722
+ events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
723
+ }
724
+ }
725
+ function mergeIntoExisting(state2, existing, states, actions, events) {
726
+ for (const name of Object.keys(state2.actions)) {
727
+ if (existing.actions[name] === state2.actions[name]) continue;
728
+ if (actions[name]) throw new Error(`Duplicate action "${name}"`);
729
+ }
730
+ for (const name of Object.keys(state2.events)) {
731
+ if (existing.events[name] === state2.events[name]) continue;
732
+ if (existing.events[name]) continue;
733
+ if (events[name]) throw new Error(`Duplicate event "${name}"`);
734
+ }
735
+ const mergedPatch = mergePatches(existing.patch, state2.patch, state2.name);
736
+ const merged = {
737
+ ...existing,
738
+ state: mergeSchemas(existing.state, state2.state, state2.name),
739
+ init: mergeInits(existing.init, state2.init),
740
+ events: { ...existing.events, ...state2.events },
741
+ actions: { ...existing.actions, ...state2.actions },
742
+ patch: mergedPatch,
743
+ on: { ...existing.on, ...state2.on },
744
+ given: { ...existing.given, ...state2.given },
745
+ snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
746
+ throw new Error(
747
+ `Duplicate snap strategy for state "${state2.name}"`
748
+ );
749
+ })() : state2.snap || existing.snap
750
+ };
751
+ states.set(state2.name, merged);
752
+ for (const name of Object.keys(merged.actions)) {
753
+ actions[name] = merged;
754
+ }
755
+ for (const name of Object.keys(state2.events)) {
756
+ if (events[name]) continue;
757
+ events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
758
+ }
759
+ }
760
+ function mergePatches(existing, incoming, stateName) {
761
+ const merged = { ...existing };
762
+ for (const name of Object.keys(incoming)) {
763
+ const existingP = existing[name];
764
+ const incomingP = incoming[name];
765
+ if (!existingP) {
766
+ merged[name] = incomingP;
767
+ continue;
768
+ }
769
+ const existingIsDefault = existingP._passthrough;
770
+ const incomingIsDefault = incomingP._passthrough;
771
+ if (!existingIsDefault && !incomingIsDefault && existingP !== incomingP) {
772
+ throw new Error(
773
+ `Duplicate custom patch for event "${name}" in state "${stateName}"`
774
+ );
775
+ }
776
+ if (existingIsDefault && !incomingIsDefault) {
777
+ merged[name] = incomingP;
778
+ }
779
+ }
780
+ return merged;
781
+ }
782
+ function mergeProjection(proj, events) {
783
+ for (const eventName of Object.keys(proj.events)) {
784
+ const projRegister = proj.events[eventName];
785
+ const existing = events[eventName];
786
+ if (!existing) {
787
+ events[eventName] = {
788
+ schema: projRegister.schema,
789
+ reactions: new Map(projRegister.reactions)
790
+ };
791
+ } else {
792
+ for (const [name, reaction] of projRegister.reactions) {
793
+ let key = name;
794
+ while (existing.reactions.has(key)) key = `${key}_p`;
795
+ existing.reactions.set(key, reaction);
796
+ }
797
+ }
798
+ }
799
+ }
800
+ var _this_ = ({ stream }) => ({
801
+ source: stream,
802
+ target: stream
803
+ });
804
+
805
+ // src/internal/drain.ts
806
+ var claim = (lagging, leading, by, millis) => store().claim(lagging, leading, by, millis);
807
+ async function fetch(leased, eventLimit) {
808
+ return Promise.all(
809
+ leased.map(async ({ stream, source, at, lagging }) => {
810
+ const events = [];
811
+ await store().query((e) => events.push(e), {
812
+ stream: source,
813
+ after: at,
814
+ limit: eventLimit
815
+ });
816
+ return { stream, source, at, lagging, events };
817
+ })
818
+ );
819
+ }
820
+ var ack = (leases) => store().ack(leases);
821
+ var block = (leases) => store().block(leases);
822
+ var subscribe = (streams) => store().subscribe(streams);
823
+
824
+ // src/internal/event-sourcing.ts
733
825
  import { patch } from "@rotorsoft/act-patch";
734
826
  import { randomUUID } from "crypto";
735
- var logger2 = log();
736
827
  async function snap(snapshot) {
737
828
  try {
738
829
  const { id, stream, name, meta, version } = snapshot.event;
739
- const snapped = await store().commit(
830
+ await store().commit(
740
831
  stream,
741
832
  [{ name: SNAP_EVENT, data: snapshot.state }],
742
833
  {
@@ -746,19 +837,18 @@ async function snap(snapshot) {
746
837
  version
747
838
  // IMPORTANT! - state events are committed right after the snapshot event
748
839
  );
749
- logger2.trace(snapped, "\u{1F7E0} snap");
750
840
  } catch (error) {
751
- logger2.error(error);
841
+ log().error(error);
752
842
  }
753
843
  }
754
844
  async function load(me, stream, callback, asOf) {
755
- const timeTravel = asOf && (asOf.before !== void 0 || asOf.created_before !== void 0 || asOf.created_after !== void 0 || asOf.limit !== void 0);
845
+ const timeTravel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
756
846
  const cached = timeTravel ? void 0 : await cache().get(stream);
757
847
  let state2 = cached?.state ?? (me.init ? me.init() : {});
758
848
  let patches = cached?.patches ?? 0;
759
849
  let snaps = cached?.snaps ?? 0;
760
850
  let event;
761
- const count = await store().query(
851
+ await store().query(
762
852
  (e) => {
763
853
  event = e;
764
854
  if (e.name === SNAP_EVENT) {
@@ -777,10 +867,6 @@ async function load(me, stream, callback, asOf) {
777
867
  ...cached ? { after: cached.event_id } : { with_snaps: true, ...asOf }
778
868
  }
779
869
  );
780
- logger2.trace(
781
- state2,
782
- `\u{1F7E2} load ${stream}${cached && count === 0 ? " (cached)" : ""}${timeTravel ? " (as-of)" : ""}`
783
- );
784
870
  return { event, state: state2, patches, snaps };
785
871
  }
786
872
  async function action(me, action2, target, payload, reactingTo, skipValidation = false) {
@@ -791,10 +877,6 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
791
877
  if (snapshot.event?.name === TOMBSTONE_EVENT)
792
878
  throw new StreamClosedError(stream);
793
879
  const expected = expectedVersion ?? snapshot.event?.version;
794
- logger2.trace(
795
- payload,
796
- `\u{1F535} ${stream}.${action2}${typeof expected === "number" ? `.${expected}` : ""}`
797
- );
798
880
  if (me.given) {
799
881
  const invariants = me.given[action2] || [];
800
882
  invariants.forEach(({ valid, description }) => {
@@ -834,10 +916,6 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
834
916
  } : void 0
835
917
  }
836
918
  };
837
- logger2.trace(
838
- emitted.map((e) => e.data),
839
- `\u{1F534} commit ${stream}.${emitted.map((e) => e.name).join(", ")}`
840
- );
841
919
  let committed;
842
920
  try {
843
921
  committed = await store().commit(
@@ -848,7 +926,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
848
926
  reactingTo ? void 0 : expected
849
927
  );
850
928
  } catch (error) {
851
- if (error.name === "ERR_CONCURRENCY") {
929
+ if (error instanceof ConcurrencyError) {
852
930
  await cache().invalidate(stream);
853
931
  }
854
932
  throw error;
@@ -862,25 +940,121 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
862
940
  });
863
941
  const last = snapshots.at(-1);
864
942
  const snapped = me.snap && me.snap(last);
865
- void cache().set(stream, {
943
+ cache().set(stream, {
866
944
  state: last.state,
867
945
  version: last.event.version,
868
946
  event_id: last.event.id,
869
947
  patches: snapped ? 0 : last.patches,
870
948
  snaps: snapped ? last.snaps + 1 : last.snaps
871
- });
949
+ }).catch((err) => log().error(err));
872
950
  if (snapped) void snap(last);
873
951
  return snapshots;
874
952
  }
875
953
 
954
+ // src/internal/tracing.ts
955
+ var traced = (inner, exit, entry) => (async (...args) => {
956
+ entry?.(...args);
957
+ const result = await inner(...args);
958
+ exit?.(result, ...args);
959
+ return result;
960
+ });
961
+ function buildEs(logger2) {
962
+ if (logger2.level !== "trace") {
963
+ return { snap, load, action };
964
+ }
965
+ return {
966
+ snap: traced(snap, void 0, (snapshot) => {
967
+ logger2.trace(
968
+ `\u{1F7E0} snap ${snapshot.event.stream}@${snapshot.event.version}`
969
+ );
970
+ }),
971
+ load: traced(load, void 0, (_me, stream, _cb, asOf) => {
972
+ logger2.trace(`\u{1F7E2} load ${stream}${asOf ? " (as-of)" : ""}`);
973
+ }),
974
+ action: traced(
975
+ action,
976
+ (snapshots, _me, _action, target) => {
977
+ const committed = snapshots.filter((s) => s.event);
978
+ if (committed.length) {
979
+ logger2.trace(
980
+ committed.map((s) => s.event.data),
981
+ `\u{1F534} commit ${target.stream}.${committed.map((s) => s.event.name).join(", ")}`
982
+ );
983
+ }
984
+ },
985
+ (_me, action2, target, payload) => {
986
+ logger2.trace(payload, `\u{1F535} ${target.stream}.${action2}`);
987
+ }
988
+ )
989
+ };
990
+ }
991
+ function buildDrain(logger2) {
992
+ if (logger2.level !== "trace") {
993
+ return {
994
+ claim,
995
+ fetch,
996
+ ack,
997
+ block,
998
+ subscribe
999
+ };
1000
+ }
1001
+ return {
1002
+ claim: traced(claim, (leased) => {
1003
+ if (leased.length) {
1004
+ const data = Object.fromEntries(
1005
+ leased.map(({ stream, at, retry }) => [stream, { at, retry }])
1006
+ );
1007
+ logger2.trace(data, ">> lease");
1008
+ }
1009
+ }),
1010
+ fetch: traced(fetch, (fetched) => {
1011
+ const data = Object.fromEntries(
1012
+ fetched.map(({ stream, source, events }) => {
1013
+ const key = source ? `${stream}<-${source}` : stream;
1014
+ const value = Object.fromEntries(
1015
+ events.map(({ id, stream: stream2, name }) => [id, { [stream2]: name }])
1016
+ );
1017
+ return [key, value];
1018
+ })
1019
+ );
1020
+ logger2.trace(data, ">> fetch");
1021
+ }),
1022
+ ack: traced(ack, (acked) => {
1023
+ if (acked.length) {
1024
+ const data = Object.fromEntries(
1025
+ acked.map(({ stream, at, retry }) => [stream, { at, retry }])
1026
+ );
1027
+ logger2.trace(data, ">> ack");
1028
+ }
1029
+ }),
1030
+ block: traced(block, (blocked) => {
1031
+ if (blocked.length) {
1032
+ const data = Object.fromEntries(
1033
+ blocked.map(({ stream, at, retry, error }) => [
1034
+ stream,
1035
+ { at, retry, error }
1036
+ ])
1037
+ );
1038
+ logger2.trace(data, ">> block");
1039
+ }
1040
+ }),
1041
+ subscribe: traced(subscribe, (result, streams) => {
1042
+ if (result.subscribed) {
1043
+ const data = streams.map(({ stream }) => stream).join(" ");
1044
+ logger2.trace(`>> correlate ${data}`);
1045
+ }
1046
+ })
1047
+ };
1048
+ }
1049
+
876
1050
  // src/act.ts
877
- var logger3 = log();
878
- var tracer = build_tracer(config().logLevel);
879
1051
  var Act = class {
880
1052
  constructor(registry, _states = /* @__PURE__ */ new Map(), batchHandlers = /* @__PURE__ */ new Map()) {
881
1053
  this.registry = registry;
882
1054
  this._states = _states;
883
1055
  this._batch_handlers = batchHandlers;
1056
+ this._es = buildEs(this._logger);
1057
+ this._cd = buildDrain(this._logger);
884
1058
  const statics = [];
885
1059
  for (const [name, register] of Object.entries(this.registry.events)) {
886
1060
  if (register.reactions.size > 0) {
@@ -940,6 +1114,12 @@ var Act = class {
940
1114
  _static_targets;
941
1115
  /** Batch handlers for static-target projections (target → handler) */
942
1116
  _batch_handlers;
1117
+ /** Event-sourcing handlers, optionally wrapped with trace decorators */
1118
+ _es;
1119
+ /** Correlate/drain pipeline ops, optionally wrapped with trace decorators */
1120
+ _cd;
1121
+ /** Logger resolved at construction time (after user port configuration) */
1122
+ _logger = log();
943
1123
  /**
944
1124
  * Executes an action on a state instance, committing resulting events.
945
1125
  *
@@ -1022,7 +1202,7 @@ var Act = class {
1022
1202
  * @see {@link ValidationError}, {@link InvariantError}, {@link ConcurrencyError}
1023
1203
  */
1024
1204
  async do(action2, target, payload, reactingTo, skipValidation = false) {
1025
- const snapshots = await action(
1205
+ const snapshots = await this._es.action(
1026
1206
  this.registry.actions[action2],
1027
1207
  action2,
1028
1208
  target,
@@ -1048,7 +1228,7 @@ var Act = class {
1048
1228
  } else {
1049
1229
  merged = this._states.get(stateOrName.name) || stateOrName;
1050
1230
  }
1051
- return await load(merged, stream, callback, asOf);
1231
+ return await this._es.load(merged, stream, callback, asOf);
1052
1232
  }
1053
1233
  /**
1054
1234
  * Queries the event store for events matching a filter.
@@ -1161,7 +1341,7 @@ var Act = class {
1161
1341
  if (payloads.length === 0) return { lease, handled: 0, at: lease.at };
1162
1342
  const stream = lease.stream;
1163
1343
  let at = payloads.at(0).event.id, handled = 0;
1164
- lease.retry > 0 && logger3.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
1344
+ lease.retry > 0 && this._logger.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
1165
1345
  const doAction = this.do.bind(this);
1166
1346
  const scopedApp = {
1167
1347
  do: doAction,
@@ -1183,16 +1363,18 @@ var Act = class {
1183
1363
  at = event.id;
1184
1364
  handled++;
1185
1365
  } catch (error) {
1186
- logger3.error(error);
1187
- const block = lease.retry >= options.maxRetries && options.blockOnError;
1188
- block && logger3.error(`Blocking ${stream} after ${lease.retry} retries.`);
1366
+ this._logger.error(error);
1367
+ const block2 = lease.retry >= options.maxRetries && options.blockOnError;
1368
+ block2 && this._logger.error(
1369
+ `Blocking ${stream} after ${lease.retry} retries.`
1370
+ );
1189
1371
  return {
1190
1372
  lease,
1191
1373
  handled,
1192
1374
  at,
1193
1375
  // only report error when nothing was handled
1194
1376
  error: handled === 0 ? error.message : void 0,
1195
- block
1377
+ block: block2
1196
1378
  };
1197
1379
  }
1198
1380
  }
@@ -1215,21 +1397,23 @@ var Act = class {
1215
1397
  const stream = lease.stream;
1216
1398
  const events = payloads.map((p) => p.event);
1217
1399
  const at = events.at(-1).id;
1218
- lease.retry > 0 && logger3.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);
1400
+ lease.retry > 0 && this._logger.warn(
1401
+ `Retrying batch ${stream}@${events[0].id} (${lease.retry}).`
1402
+ );
1219
1403
  try {
1220
1404
  await batchHandler(events, stream);
1221
1405
  return { lease, handled: events.length, at };
1222
1406
  } catch (error) {
1223
- logger3.error(error);
1407
+ this._logger.error(error);
1224
1408
  const { options } = payloads[0];
1225
- const block = lease.retry >= options.maxRetries && options.blockOnError;
1226
- block && logger3.error(`Blocking ${stream} after ${lease.retry} retries.`);
1409
+ const block2 = lease.retry >= options.maxRetries && options.blockOnError;
1410
+ block2 && this._logger.error(`Blocking ${stream} after ${lease.retry} retries.`);
1227
1411
  return {
1228
1412
  lease,
1229
1413
  handled: 0,
1230
1414
  at: lease.at,
1231
1415
  error: error.message,
1232
- block
1416
+ block: block2
1233
1417
  };
1234
1418
  }
1235
1419
  }
@@ -1285,7 +1469,7 @@ var Act = class {
1285
1469
  this._drain_locked = true;
1286
1470
  const lagging = Math.ceil(streamLimit * this._drain_lag2lead_ratio);
1287
1471
  const leading = streamLimit - lagging;
1288
- const leased = await store().claim(
1472
+ const leased = await this._cd.claim(
1289
1473
  lagging,
1290
1474
  leading,
1291
1475
  randomUUID2(),
@@ -1295,17 +1479,7 @@ var Act = class {
1295
1479
  this._needs_drain = false;
1296
1480
  return { fetched: [], leased: [], acked: [], blocked: [] };
1297
1481
  }
1298
- const fetched = await Promise.all(
1299
- leased.map(async ({ stream, source, at, lagging: lagging2 }) => {
1300
- const events = await this.query_array({
1301
- stream: source,
1302
- after: at,
1303
- limit: eventLimit
1304
- });
1305
- return { stream, source, at, lagging: lagging2, events };
1306
- })
1307
- );
1308
- tracer.fetched(fetched);
1482
+ const fetched = await this._cd.fetch(leased, eventLimit);
1309
1483
  const payloadsMap = /* @__PURE__ */ new Map();
1310
1484
  const fetch_window_at = fetched.reduce(
1311
1485
  (max, { at, events }) => Math.max(max, events.at(-1)?.id || at),
@@ -1322,7 +1496,6 @@ var Act = class {
1322
1496
  });
1323
1497
  payloadsMap.set(stream, payloads);
1324
1498
  });
1325
- tracer.leased(leased);
1326
1499
  const handled = await Promise.all(
1327
1500
  leased.map((lease) => {
1328
1501
  const streamFetch = fetched.find((f) => f.stream === lease.stream);
@@ -1346,27 +1519,21 @@ var Act = class {
1346
1519
  const leading_avg = leading > 0 ? leading_handled / leading : 0;
1347
1520
  const total = lagging_avg + leading_avg;
1348
1521
  this._drain_lag2lead_ratio = total > 0 ? Math.max(0.2, Math.min(0.8, lagging_avg / total)) : 0.5;
1349
- const acked = await store().ack(
1522
+ const acked = await this._cd.ack(
1350
1523
  handled.filter(({ error }) => !error).map(({ at, lease }) => ({ ...lease, at }))
1351
1524
  );
1352
- if (acked.length) {
1353
- tracer.acked(acked);
1354
- this.emit("acked", acked);
1355
- }
1356
- const blocked = await store().block(
1357
- handled.filter(({ block }) => block).map(({ lease, error }) => ({ ...lease, error }))
1525
+ if (acked.length) this.emit("acked", acked);
1526
+ const blocked = await this._cd.block(
1527
+ handled.filter(({ block: block2 }) => block2).map(({ lease, error }) => ({ ...lease, error }))
1358
1528
  );
1359
- if (blocked.length) {
1360
- tracer.blocked(blocked);
1361
- this.emit("blocked", blocked);
1362
- }
1529
+ if (blocked.length) this.emit("blocked", blocked);
1363
1530
  const result = { fetched, leased, acked, blocked };
1364
1531
  const hasErrors = handled.some(({ error }) => error);
1365
1532
  if (!acked.length && !blocked.length && !hasErrors)
1366
1533
  this._needs_drain = false;
1367
1534
  return result;
1368
1535
  } catch (error) {
1369
- logger3.error(error);
1536
+ this._logger.error(error);
1370
1537
  } finally {
1371
1538
  this._drain_locked = false;
1372
1539
  }
@@ -1472,10 +1639,9 @@ var Act = class {
1472
1639
  stream,
1473
1640
  source
1474
1641
  }));
1475
- const { subscribed } = await store().subscribe(streams);
1642
+ const { subscribed } = await this._cd.subscribe(streams);
1476
1643
  this._correlation_checkpoint = last_id;
1477
1644
  if (subscribed) {
1478
- tracer.correlated(streams);
1479
1645
  for (const { stream } of streams) {
1480
1646
  this._subscribed_statics.add(stream);
1481
1647
  }
@@ -1740,7 +1906,7 @@ var Act = class {
1740
1906
  if (mergedState) {
1741
1907
  await Promise.all(
1742
1908
  guarded.filter((s) => targetMap.get(s)?.restart).map(async (stream) => {
1743
- const snap2 = await load(mergedState, stream);
1909
+ const snap2 = await this._es.load(mergedState, stream);
1744
1910
  seedStates.set(stream, snap2.state);
1745
1911
  })
1746
1912
  );
@@ -1847,139 +2013,13 @@ var Act = class {
1847
2013
  if (!made_progress) break;
1848
2014
  }
1849
2015
  if (lastDrain) this.emit("settled", lastDrain);
1850
- })().catch((err) => logger3.error(err)).finally(() => {
2016
+ })().catch((err) => this._logger.error(err)).finally(() => {
1851
2017
  this._settling = false;
1852
2018
  });
1853
2019
  }, debounceMs);
1854
2020
  }
1855
2021
  };
1856
2022
 
1857
- // src/merge.ts
1858
- import { ZodObject } from "zod";
1859
- function baseTypeName(zodType) {
1860
- let t = zodType;
1861
- while (typeof t.unwrap === "function") {
1862
- t = t.unwrap();
1863
- }
1864
- return t.constructor.name;
1865
- }
1866
- function mergeSchemas(existing, incoming, stateName) {
1867
- if (existing instanceof ZodObject && incoming instanceof ZodObject) {
1868
- const existingShape = existing.shape;
1869
- const incomingShape = incoming.shape;
1870
- for (const key of Object.keys(incomingShape)) {
1871
- if (key in existingShape) {
1872
- const existingBase = baseTypeName(existingShape[key]);
1873
- const incomingBase = baseTypeName(incomingShape[key]);
1874
- if (existingBase !== incomingBase) {
1875
- throw new Error(
1876
- `Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
1877
- );
1878
- }
1879
- }
1880
- }
1881
- return existing.extend(incomingShape);
1882
- }
1883
- return existing;
1884
- }
1885
- function mergeInits(existing, incoming) {
1886
- return () => ({ ...existing(), ...incoming() });
1887
- }
1888
- function registerState(state2, states, actions, events) {
1889
- if (states.has(state2.name)) {
1890
- const existing = states.get(state2.name);
1891
- for (const name of Object.keys(state2.actions)) {
1892
- if (existing.actions[name] === state2.actions[name]) continue;
1893
- if (actions[name]) throw new Error(`Duplicate action "${name}"`);
1894
- }
1895
- for (const name of Object.keys(state2.events)) {
1896
- if (existing.events[name] === state2.events[name]) continue;
1897
- if (existing.events[name]) continue;
1898
- if (events[name]) throw new Error(`Duplicate event "${name}"`);
1899
- }
1900
- const mergedPatch = { ...existing.patch };
1901
- for (const name of Object.keys(state2.patch)) {
1902
- const existingP = existing.patch[name];
1903
- const incomingP = state2.patch[name];
1904
- if (!existingP) {
1905
- mergedPatch[name] = incomingP;
1906
- } else {
1907
- const existingIsDefault = existingP._passthrough;
1908
- const incomingIsDefault = incomingP._passthrough;
1909
- if (!existingIsDefault && !incomingIsDefault && existingP !== incomingP) {
1910
- throw new Error(
1911
- `Duplicate custom patch for event "${name}" in state "${state2.name}"`
1912
- );
1913
- }
1914
- if (existingIsDefault && !incomingIsDefault) {
1915
- mergedPatch[name] = incomingP;
1916
- }
1917
- }
1918
- }
1919
- const merged = {
1920
- ...existing,
1921
- state: mergeSchemas(existing.state, state2.state, state2.name),
1922
- init: mergeInits(existing.init, state2.init),
1923
- events: { ...existing.events, ...state2.events },
1924
- actions: { ...existing.actions, ...state2.actions },
1925
- patch: mergedPatch,
1926
- on: { ...existing.on, ...state2.on },
1927
- given: { ...existing.given, ...state2.given },
1928
- snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
1929
- throw new Error(
1930
- `Duplicate snap strategy for state "${state2.name}"`
1931
- );
1932
- })() : state2.snap || existing.snap
1933
- };
1934
- states.set(state2.name, merged);
1935
- for (const name of Object.keys(merged.actions)) {
1936
- actions[name] = merged;
1937
- }
1938
- for (const name of Object.keys(state2.events)) {
1939
- if (events[name]) continue;
1940
- events[name] = {
1941
- schema: state2.events[name],
1942
- reactions: /* @__PURE__ */ new Map()
1943
- };
1944
- }
1945
- } else {
1946
- states.set(state2.name, state2);
1947
- for (const name of Object.keys(state2.actions)) {
1948
- if (actions[name]) throw new Error(`Duplicate action "${name}"`);
1949
- actions[name] = state2;
1950
- }
1951
- for (const name of Object.keys(state2.events)) {
1952
- if (events[name]) throw new Error(`Duplicate event "${name}"`);
1953
- events[name] = {
1954
- schema: state2.events[name],
1955
- reactions: /* @__PURE__ */ new Map()
1956
- };
1957
- }
1958
- }
1959
- }
1960
- function mergeProjection(proj, events) {
1961
- for (const eventName of Object.keys(proj.events)) {
1962
- const projRegister = proj.events[eventName];
1963
- const existing = events[eventName];
1964
- if (!existing) {
1965
- events[eventName] = {
1966
- schema: projRegister.schema,
1967
- reactions: new Map(projRegister.reactions)
1968
- };
1969
- } else {
1970
- for (const [name, reaction] of projRegister.reactions) {
1971
- let key = name;
1972
- while (existing.reactions.has(key)) key = `${key}_p`;
1973
- existing.reactions.set(key, reaction);
1974
- }
1975
- }
1976
- }
1977
- }
1978
- var _this_ = ({ stream }) => ({
1979
- source: stream,
1980
- target: stream
1981
- });
1982
-
1983
2023
  // src/act-builder.ts
1984
2024
  function act(states = /* @__PURE__ */ new Map(), registry = {
1985
2025
  actions: {},
@@ -2220,8 +2260,9 @@ function state(entry) {
2220
2260
  emits(events) {
2221
2261
  const defaultPatch = Object.fromEntries(
2222
2262
  Object.keys(events).map((k) => {
2223
- const fn = ({ data }) => data;
2224
- fn._passthrough = true;
2263
+ const fn = Object.assign(({ data }) => data, {
2264
+ _passthrough: true
2265
+ });
2225
2266
  return [k, fn];
2226
2267
  })
2227
2268
  );
@@ -2322,7 +2363,6 @@ export {
2322
2363
  ValidationError,
2323
2364
  ZodEmpty,
2324
2365
  act,
2325
- build_tracer,
2326
2366
  cache,
2327
2367
  config,
2328
2368
  dispose,