@rotorsoft/act 0.32.1 → 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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +6 -10
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/InMemoryStore.d.ts +2 -4
- package/dist/@types/adapters/InMemoryStore.d.ts.map +1 -1
- package/dist/@types/internal/drain.d.ts +2 -6
- package/dist/@types/internal/drain.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/index.d.ts +9 -4
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/internal/merge.d.ts +1 -25
- package/dist/@types/internal/merge.d.ts.map +1 -1
- package/dist/@types/internal/tracing.d.ts +9 -10
- package/dist/@types/internal/tracing.d.ts.map +1 -1
- package/dist/@types/state-builder.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +13 -0
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +2 -6
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +9 -3
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/index.cjs +232 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +232 -243
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -672,6 +672,136 @@ process.once("unhandledRejection", async (arg) => {
|
|
|
672
672
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
673
673
|
import EventEmitter from "events";
|
|
674
674
|
|
|
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
|
+
|
|
675
805
|
// src/internal/drain.ts
|
|
676
806
|
var claim = (lagging, leading, by, millis) => store().claim(lagging, leading, by, millis);
|
|
677
807
|
async function fetch(leased, eventLimit) {
|
|
@@ -694,7 +824,6 @@ var subscribe = (streams) => store().subscribe(streams);
|
|
|
694
824
|
// src/internal/event-sourcing.ts
|
|
695
825
|
import { patch } from "@rotorsoft/act-patch";
|
|
696
826
|
import { randomUUID } from "crypto";
|
|
697
|
-
var logger2 = log();
|
|
698
827
|
async function snap(snapshot) {
|
|
699
828
|
try {
|
|
700
829
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
@@ -709,11 +838,11 @@ async function snap(snapshot) {
|
|
|
709
838
|
// IMPORTANT! - state events are committed right after the snapshot event
|
|
710
839
|
);
|
|
711
840
|
} catch (error) {
|
|
712
|
-
|
|
841
|
+
log().error(error);
|
|
713
842
|
}
|
|
714
843
|
}
|
|
715
844
|
async function load(me, stream, callback, asOf) {
|
|
716
|
-
const timeTravel = asOf && (asOf.
|
|
845
|
+
const timeTravel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
|
|
717
846
|
const cached = timeTravel ? void 0 : await cache().get(stream);
|
|
718
847
|
let state2 = cached?.state ?? (me.init ? me.init() : {});
|
|
719
848
|
let patches = cached?.patches ?? 0;
|
|
@@ -797,7 +926,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
797
926
|
reactingTo ? void 0 : expected
|
|
798
927
|
);
|
|
799
928
|
} catch (error) {
|
|
800
|
-
if (error
|
|
929
|
+
if (error instanceof ConcurrencyError) {
|
|
801
930
|
await cache().invalidate(stream);
|
|
802
931
|
}
|
|
803
932
|
throw error;
|
|
@@ -811,241 +940,56 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
811
940
|
});
|
|
812
941
|
const last = snapshots.at(-1);
|
|
813
942
|
const snapped = me.snap && me.snap(last);
|
|
814
|
-
|
|
943
|
+
cache().set(stream, {
|
|
815
944
|
state: last.state,
|
|
816
945
|
version: last.event.version,
|
|
817
946
|
event_id: last.event.id,
|
|
818
947
|
patches: snapped ? 0 : last.patches,
|
|
819
948
|
snaps: snapped ? last.snaps + 1 : last.snaps
|
|
820
|
-
});
|
|
949
|
+
}).catch((err) => log().error(err));
|
|
821
950
|
if (snapped) void snap(last);
|
|
822
951
|
return snapshots;
|
|
823
952
|
}
|
|
824
953
|
|
|
825
|
-
// src/internal/merge.ts
|
|
826
|
-
import { ZodObject } from "zod";
|
|
827
|
-
function baseTypeName(zodType) {
|
|
828
|
-
let t = zodType;
|
|
829
|
-
while (typeof t.unwrap === "function") {
|
|
830
|
-
t = t.unwrap();
|
|
831
|
-
}
|
|
832
|
-
return t.constructor.name;
|
|
833
|
-
}
|
|
834
|
-
function mergeSchemas(existing, incoming, stateName) {
|
|
835
|
-
if (existing instanceof ZodObject && incoming instanceof ZodObject) {
|
|
836
|
-
const existingShape = existing.shape;
|
|
837
|
-
const incomingShape = incoming.shape;
|
|
838
|
-
for (const key of Object.keys(incomingShape)) {
|
|
839
|
-
if (key in existingShape) {
|
|
840
|
-
const existingBase = baseTypeName(existingShape[key]);
|
|
841
|
-
const incomingBase = baseTypeName(incomingShape[key]);
|
|
842
|
-
if (existingBase !== incomingBase) {
|
|
843
|
-
throw new Error(
|
|
844
|
-
`Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
|
|
845
|
-
);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
return existing.extend(incomingShape);
|
|
850
|
-
}
|
|
851
|
-
return existing;
|
|
852
|
-
}
|
|
853
|
-
function mergeInits(existing, incoming) {
|
|
854
|
-
return () => ({ ...existing(), ...incoming() });
|
|
855
|
-
}
|
|
856
|
-
function registerState(state2, states, actions, events) {
|
|
857
|
-
if (states.has(state2.name)) {
|
|
858
|
-
const existing = states.get(state2.name);
|
|
859
|
-
for (const name of Object.keys(state2.actions)) {
|
|
860
|
-
if (existing.actions[name] === state2.actions[name]) continue;
|
|
861
|
-
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
862
|
-
}
|
|
863
|
-
for (const name of Object.keys(state2.events)) {
|
|
864
|
-
if (existing.events[name] === state2.events[name]) continue;
|
|
865
|
-
if (existing.events[name]) continue;
|
|
866
|
-
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
867
|
-
}
|
|
868
|
-
const mergedPatch = { ...existing.patch };
|
|
869
|
-
for (const name of Object.keys(state2.patch)) {
|
|
870
|
-
const existingP = existing.patch[name];
|
|
871
|
-
const incomingP = state2.patch[name];
|
|
872
|
-
if (!existingP) {
|
|
873
|
-
mergedPatch[name] = incomingP;
|
|
874
|
-
} else {
|
|
875
|
-
const existingIsDefault = existingP._passthrough;
|
|
876
|
-
const incomingIsDefault = incomingP._passthrough;
|
|
877
|
-
if (!existingIsDefault && !incomingIsDefault && existingP !== incomingP) {
|
|
878
|
-
throw new Error(
|
|
879
|
-
`Duplicate custom patch for event "${name}" in state "${state2.name}"`
|
|
880
|
-
);
|
|
881
|
-
}
|
|
882
|
-
if (existingIsDefault && !incomingIsDefault) {
|
|
883
|
-
mergedPatch[name] = incomingP;
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
const merged = {
|
|
888
|
-
...existing,
|
|
889
|
-
state: mergeSchemas(existing.state, state2.state, state2.name),
|
|
890
|
-
init: mergeInits(existing.init, state2.init),
|
|
891
|
-
events: { ...existing.events, ...state2.events },
|
|
892
|
-
actions: { ...existing.actions, ...state2.actions },
|
|
893
|
-
patch: mergedPatch,
|
|
894
|
-
on: { ...existing.on, ...state2.on },
|
|
895
|
-
given: { ...existing.given, ...state2.given },
|
|
896
|
-
snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
|
|
897
|
-
throw new Error(
|
|
898
|
-
`Duplicate snap strategy for state "${state2.name}"`
|
|
899
|
-
);
|
|
900
|
-
})() : state2.snap || existing.snap
|
|
901
|
-
};
|
|
902
|
-
states.set(state2.name, merged);
|
|
903
|
-
for (const name of Object.keys(merged.actions)) {
|
|
904
|
-
actions[name] = merged;
|
|
905
|
-
}
|
|
906
|
-
for (const name of Object.keys(state2.events)) {
|
|
907
|
-
if (events[name]) continue;
|
|
908
|
-
events[name] = {
|
|
909
|
-
schema: state2.events[name],
|
|
910
|
-
reactions: /* @__PURE__ */ new Map()
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
} else {
|
|
914
|
-
states.set(state2.name, state2);
|
|
915
|
-
for (const name of Object.keys(state2.actions)) {
|
|
916
|
-
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
917
|
-
actions[name] = state2;
|
|
918
|
-
}
|
|
919
|
-
for (const name of Object.keys(state2.events)) {
|
|
920
|
-
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
921
|
-
events[name] = {
|
|
922
|
-
schema: state2.events[name],
|
|
923
|
-
reactions: /* @__PURE__ */ new Map()
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
function mergeProjection(proj, events) {
|
|
929
|
-
for (const eventName of Object.keys(proj.events)) {
|
|
930
|
-
const projRegister = proj.events[eventName];
|
|
931
|
-
const existing = events[eventName];
|
|
932
|
-
if (!existing) {
|
|
933
|
-
events[eventName] = {
|
|
934
|
-
schema: projRegister.schema,
|
|
935
|
-
reactions: new Map(projRegister.reactions)
|
|
936
|
-
};
|
|
937
|
-
} else {
|
|
938
|
-
for (const [name, reaction] of projRegister.reactions) {
|
|
939
|
-
let key = name;
|
|
940
|
-
while (existing.reactions.has(key)) key = `${key}_p`;
|
|
941
|
-
existing.reactions.set(key, reaction);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
var _this_ = ({ stream }) => ({
|
|
947
|
-
source: stream,
|
|
948
|
-
target: stream
|
|
949
|
-
});
|
|
950
|
-
|
|
951
954
|
// src/internal/tracing.ts
|
|
952
|
-
var
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
logger3.trace(`\u{1F7E2} load ${stream}${asOf ? " (as-of)" : ""}`);
|
|
961
|
-
return inner(me, stream, callback, asOf);
|
|
962
|
-
};
|
|
963
|
-
var withActionTrace = (inner) => async (me, action2, target, payload, reactingTo, skipValidation) => {
|
|
964
|
-
logger3.trace(payload, `\u{1F535} ${target.stream}.${action2}`);
|
|
965
|
-
const snapshots = await inner(
|
|
966
|
-
me,
|
|
967
|
-
action2,
|
|
968
|
-
target,
|
|
969
|
-
payload,
|
|
970
|
-
reactingTo,
|
|
971
|
-
skipValidation
|
|
972
|
-
);
|
|
973
|
-
const committed = snapshots.filter((s) => s.event);
|
|
974
|
-
if (committed.length) {
|
|
975
|
-
logger3.trace(
|
|
976
|
-
committed.map((s) => s.event.data),
|
|
977
|
-
`\u{1F534} commit ${target.stream}.${committed.map((s) => s.event.name).join(", ")}`
|
|
978
|
-
);
|
|
979
|
-
}
|
|
980
|
-
return snapshots;
|
|
981
|
-
};
|
|
982
|
-
function buildEs(level) {
|
|
983
|
-
if (level !== "trace") {
|
|
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") {
|
|
984
963
|
return { snap, load, action };
|
|
985
964
|
}
|
|
986
965
|
return {
|
|
987
|
-
snap:
|
|
988
|
-
|
|
989
|
-
|
|
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
|
+
)
|
|
990
989
|
};
|
|
991
990
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
if (leased.length) {
|
|
995
|
-
const data = Object.fromEntries(
|
|
996
|
-
leased.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
997
|
-
);
|
|
998
|
-
logger3.trace(data, ">> lease");
|
|
999
|
-
}
|
|
1000
|
-
return leased;
|
|
1001
|
-
};
|
|
1002
|
-
var withFetchTrace = (inner) => async (leased, eventLimit) => {
|
|
1003
|
-
const fetched = await inner(leased, eventLimit);
|
|
1004
|
-
const data = Object.fromEntries(
|
|
1005
|
-
fetched.map(({ stream, source, events }) => {
|
|
1006
|
-
const key = source ? `${stream}<-${source}` : stream;
|
|
1007
|
-
const value = Object.fromEntries(
|
|
1008
|
-
events.map(({ id, stream: stream2, name }) => [id, { [stream2]: name }])
|
|
1009
|
-
);
|
|
1010
|
-
return [key, value];
|
|
1011
|
-
})
|
|
1012
|
-
);
|
|
1013
|
-
logger3.trace(data, ">> fetch");
|
|
1014
|
-
return fetched;
|
|
1015
|
-
};
|
|
1016
|
-
var withAckTrace = (inner) => async (leases) => {
|
|
1017
|
-
const acked = await inner(leases);
|
|
1018
|
-
if (acked.length) {
|
|
1019
|
-
const data = Object.fromEntries(
|
|
1020
|
-
acked.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1021
|
-
);
|
|
1022
|
-
logger3.trace(data, ">> ack");
|
|
1023
|
-
}
|
|
1024
|
-
return acked;
|
|
1025
|
-
};
|
|
1026
|
-
var withBlockTrace = (inner) => async (leases) => {
|
|
1027
|
-
const blocked = await inner(leases);
|
|
1028
|
-
if (blocked.length) {
|
|
1029
|
-
const data = Object.fromEntries(
|
|
1030
|
-
blocked.map(({ stream, at, retry, error }) => [
|
|
1031
|
-
stream,
|
|
1032
|
-
{ at, retry, error }
|
|
1033
|
-
])
|
|
1034
|
-
);
|
|
1035
|
-
logger3.trace(data, ">> block");
|
|
1036
|
-
}
|
|
1037
|
-
return blocked;
|
|
1038
|
-
};
|
|
1039
|
-
var withSubscribeTrace = (inner) => async (streams) => {
|
|
1040
|
-
const result = await inner(streams);
|
|
1041
|
-
if (result.subscribed) {
|
|
1042
|
-
const data = streams.map(({ stream }) => stream).join(" ");
|
|
1043
|
-
logger3.trace(`>> correlate ${data}`);
|
|
1044
|
-
}
|
|
1045
|
-
return result;
|
|
1046
|
-
};
|
|
1047
|
-
function buildDrain(level) {
|
|
1048
|
-
if (level !== "trace") {
|
|
991
|
+
function buildDrain(logger2) {
|
|
992
|
+
if (logger2.level !== "trace") {
|
|
1049
993
|
return {
|
|
1050
994
|
claim,
|
|
1051
995
|
fetch,
|
|
@@ -1055,24 +999,62 @@ function buildDrain(level) {
|
|
|
1055
999
|
};
|
|
1056
1000
|
}
|
|
1057
1001
|
return {
|
|
1058
|
-
claim:
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
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
|
+
})
|
|
1063
1047
|
};
|
|
1064
1048
|
}
|
|
1065
1049
|
|
|
1066
1050
|
// src/act.ts
|
|
1067
|
-
var logger4 = log();
|
|
1068
1051
|
var Act = class {
|
|
1069
1052
|
constructor(registry, _states = /* @__PURE__ */ new Map(), batchHandlers = /* @__PURE__ */ new Map()) {
|
|
1070
1053
|
this.registry = registry;
|
|
1071
1054
|
this._states = _states;
|
|
1072
1055
|
this._batch_handlers = batchHandlers;
|
|
1073
|
-
|
|
1074
|
-
this.
|
|
1075
|
-
this._cd = buildDrain(level);
|
|
1056
|
+
this._es = buildEs(this._logger);
|
|
1057
|
+
this._cd = buildDrain(this._logger);
|
|
1076
1058
|
const statics = [];
|
|
1077
1059
|
for (const [name, register] of Object.entries(this.registry.events)) {
|
|
1078
1060
|
if (register.reactions.size > 0) {
|
|
@@ -1136,6 +1118,8 @@ var Act = class {
|
|
|
1136
1118
|
_es;
|
|
1137
1119
|
/** Correlate/drain pipeline ops, optionally wrapped with trace decorators */
|
|
1138
1120
|
_cd;
|
|
1121
|
+
/** Logger resolved at construction time (after user port configuration) */
|
|
1122
|
+
_logger = log();
|
|
1139
1123
|
/**
|
|
1140
1124
|
* Executes an action on a state instance, committing resulting events.
|
|
1141
1125
|
*
|
|
@@ -1357,7 +1341,7 @@ var Act = class {
|
|
|
1357
1341
|
if (payloads.length === 0) return { lease, handled: 0, at: lease.at };
|
|
1358
1342
|
const stream = lease.stream;
|
|
1359
1343
|
let at = payloads.at(0).event.id, handled = 0;
|
|
1360
|
-
lease.retry > 0 &&
|
|
1344
|
+
lease.retry > 0 && this._logger.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
|
|
1361
1345
|
const doAction = this.do.bind(this);
|
|
1362
1346
|
const scopedApp = {
|
|
1363
1347
|
do: doAction,
|
|
@@ -1379,9 +1363,11 @@ var Act = class {
|
|
|
1379
1363
|
at = event.id;
|
|
1380
1364
|
handled++;
|
|
1381
1365
|
} catch (error) {
|
|
1382
|
-
|
|
1366
|
+
this._logger.error(error);
|
|
1383
1367
|
const block2 = lease.retry >= options.maxRetries && options.blockOnError;
|
|
1384
|
-
block2 &&
|
|
1368
|
+
block2 && this._logger.error(
|
|
1369
|
+
`Blocking ${stream} after ${lease.retry} retries.`
|
|
1370
|
+
);
|
|
1385
1371
|
return {
|
|
1386
1372
|
lease,
|
|
1387
1373
|
handled,
|
|
@@ -1411,15 +1397,17 @@ var Act = class {
|
|
|
1411
1397
|
const stream = lease.stream;
|
|
1412
1398
|
const events = payloads.map((p) => p.event);
|
|
1413
1399
|
const at = events.at(-1).id;
|
|
1414
|
-
lease.retry > 0 &&
|
|
1400
|
+
lease.retry > 0 && this._logger.warn(
|
|
1401
|
+
`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`
|
|
1402
|
+
);
|
|
1415
1403
|
try {
|
|
1416
1404
|
await batchHandler(events, stream);
|
|
1417
1405
|
return { lease, handled: events.length, at };
|
|
1418
1406
|
} catch (error) {
|
|
1419
|
-
|
|
1407
|
+
this._logger.error(error);
|
|
1420
1408
|
const { options } = payloads[0];
|
|
1421
1409
|
const block2 = lease.retry >= options.maxRetries && options.blockOnError;
|
|
1422
|
-
block2 &&
|
|
1410
|
+
block2 && this._logger.error(`Blocking ${stream} after ${lease.retry} retries.`);
|
|
1423
1411
|
return {
|
|
1424
1412
|
lease,
|
|
1425
1413
|
handled: 0,
|
|
@@ -1545,7 +1533,7 @@ var Act = class {
|
|
|
1545
1533
|
this._needs_drain = false;
|
|
1546
1534
|
return result;
|
|
1547
1535
|
} catch (error) {
|
|
1548
|
-
|
|
1536
|
+
this._logger.error(error);
|
|
1549
1537
|
} finally {
|
|
1550
1538
|
this._drain_locked = false;
|
|
1551
1539
|
}
|
|
@@ -2025,7 +2013,7 @@ var Act = class {
|
|
|
2025
2013
|
if (!made_progress) break;
|
|
2026
2014
|
}
|
|
2027
2015
|
if (lastDrain) this.emit("settled", lastDrain);
|
|
2028
|
-
})().catch((err) =>
|
|
2016
|
+
})().catch((err) => this._logger.error(err)).finally(() => {
|
|
2029
2017
|
this._settling = false;
|
|
2030
2018
|
});
|
|
2031
2019
|
}, debounceMs);
|
|
@@ -2272,8 +2260,9 @@ function state(entry) {
|
|
|
2272
2260
|
emits(events) {
|
|
2273
2261
|
const defaultPatch = Object.fromEntries(
|
|
2274
2262
|
Object.keys(events).map((k) => {
|
|
2275
|
-
const fn = ({ data }) => data
|
|
2276
|
-
|
|
2263
|
+
const fn = Object.assign(({ data }) => data, {
|
|
2264
|
+
_passthrough: true
|
|
2265
|
+
});
|
|
2277
2266
|
return [k, fn];
|
|
2278
2267
|
})
|
|
2279
2268
|
);
|