@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.cjs
CHANGED
|
@@ -838,6 +838,136 @@ process.once("unhandledRejection", async (arg) => {
|
|
|
838
838
|
var import_crypto2 = require("crypto");
|
|
839
839
|
var import_events = __toESM(require("events"), 1);
|
|
840
840
|
|
|
841
|
+
// src/internal/merge.ts
|
|
842
|
+
var import_zod4 = require("zod");
|
|
843
|
+
function baseTypeName(zodType) {
|
|
844
|
+
let t = zodType;
|
|
845
|
+
while (typeof t.unwrap === "function") {
|
|
846
|
+
t = t.unwrap();
|
|
847
|
+
}
|
|
848
|
+
return t.constructor.name;
|
|
849
|
+
}
|
|
850
|
+
function mergeSchemas(existing, incoming, stateName) {
|
|
851
|
+
if (existing instanceof import_zod4.ZodObject && incoming instanceof import_zod4.ZodObject) {
|
|
852
|
+
const existingShape = existing.shape;
|
|
853
|
+
const incomingShape = incoming.shape;
|
|
854
|
+
for (const key of Object.keys(incomingShape)) {
|
|
855
|
+
if (key in existingShape) {
|
|
856
|
+
const existingBase = baseTypeName(existingShape[key]);
|
|
857
|
+
const incomingBase = baseTypeName(incomingShape[key]);
|
|
858
|
+
if (existingBase !== incomingBase) {
|
|
859
|
+
throw new Error(
|
|
860
|
+
`Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return existing.extend(incomingShape);
|
|
866
|
+
}
|
|
867
|
+
return existing;
|
|
868
|
+
}
|
|
869
|
+
function mergeInits(existing, incoming) {
|
|
870
|
+
return () => ({ ...existing(), ...incoming() });
|
|
871
|
+
}
|
|
872
|
+
function registerState(state2, states, actions, events) {
|
|
873
|
+
const existing = states.get(state2.name);
|
|
874
|
+
if (existing) {
|
|
875
|
+
mergeIntoExisting(state2, existing, states, actions, events);
|
|
876
|
+
} else {
|
|
877
|
+
registerNewState(state2, states, actions, events);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function registerNewState(state2, states, actions, events) {
|
|
881
|
+
states.set(state2.name, state2);
|
|
882
|
+
for (const name of Object.keys(state2.actions)) {
|
|
883
|
+
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
884
|
+
actions[name] = state2;
|
|
885
|
+
}
|
|
886
|
+
for (const name of Object.keys(state2.events)) {
|
|
887
|
+
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
888
|
+
events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
function mergeIntoExisting(state2, existing, states, actions, events) {
|
|
892
|
+
for (const name of Object.keys(state2.actions)) {
|
|
893
|
+
if (existing.actions[name] === state2.actions[name]) continue;
|
|
894
|
+
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
895
|
+
}
|
|
896
|
+
for (const name of Object.keys(state2.events)) {
|
|
897
|
+
if (existing.events[name] === state2.events[name]) continue;
|
|
898
|
+
if (existing.events[name]) continue;
|
|
899
|
+
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
900
|
+
}
|
|
901
|
+
const mergedPatch = mergePatches(existing.patch, state2.patch, state2.name);
|
|
902
|
+
const merged = {
|
|
903
|
+
...existing,
|
|
904
|
+
state: mergeSchemas(existing.state, state2.state, state2.name),
|
|
905
|
+
init: mergeInits(existing.init, state2.init),
|
|
906
|
+
events: { ...existing.events, ...state2.events },
|
|
907
|
+
actions: { ...existing.actions, ...state2.actions },
|
|
908
|
+
patch: mergedPatch,
|
|
909
|
+
on: { ...existing.on, ...state2.on },
|
|
910
|
+
given: { ...existing.given, ...state2.given },
|
|
911
|
+
snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
|
|
912
|
+
throw new Error(
|
|
913
|
+
`Duplicate snap strategy for state "${state2.name}"`
|
|
914
|
+
);
|
|
915
|
+
})() : state2.snap || existing.snap
|
|
916
|
+
};
|
|
917
|
+
states.set(state2.name, merged);
|
|
918
|
+
for (const name of Object.keys(merged.actions)) {
|
|
919
|
+
actions[name] = merged;
|
|
920
|
+
}
|
|
921
|
+
for (const name of Object.keys(state2.events)) {
|
|
922
|
+
if (events[name]) continue;
|
|
923
|
+
events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function mergePatches(existing, incoming, stateName) {
|
|
927
|
+
const merged = { ...existing };
|
|
928
|
+
for (const name of Object.keys(incoming)) {
|
|
929
|
+
const existingP = existing[name];
|
|
930
|
+
const incomingP = incoming[name];
|
|
931
|
+
if (!existingP) {
|
|
932
|
+
merged[name] = incomingP;
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
const existingIsDefault = existingP._passthrough;
|
|
936
|
+
const incomingIsDefault = incomingP._passthrough;
|
|
937
|
+
if (!existingIsDefault && !incomingIsDefault && existingP !== incomingP) {
|
|
938
|
+
throw new Error(
|
|
939
|
+
`Duplicate custom patch for event "${name}" in state "${stateName}"`
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
if (existingIsDefault && !incomingIsDefault) {
|
|
943
|
+
merged[name] = incomingP;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return merged;
|
|
947
|
+
}
|
|
948
|
+
function mergeProjection(proj, events) {
|
|
949
|
+
for (const eventName of Object.keys(proj.events)) {
|
|
950
|
+
const projRegister = proj.events[eventName];
|
|
951
|
+
const existing = events[eventName];
|
|
952
|
+
if (!existing) {
|
|
953
|
+
events[eventName] = {
|
|
954
|
+
schema: projRegister.schema,
|
|
955
|
+
reactions: new Map(projRegister.reactions)
|
|
956
|
+
};
|
|
957
|
+
} else {
|
|
958
|
+
for (const [name, reaction] of projRegister.reactions) {
|
|
959
|
+
let key = name;
|
|
960
|
+
while (existing.reactions.has(key)) key = `${key}_p`;
|
|
961
|
+
existing.reactions.set(key, reaction);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
var _this_ = ({ stream }) => ({
|
|
967
|
+
source: stream,
|
|
968
|
+
target: stream
|
|
969
|
+
});
|
|
970
|
+
|
|
841
971
|
// src/internal/drain.ts
|
|
842
972
|
var claim = (lagging, leading, by, millis) => store().claim(lagging, leading, by, millis);
|
|
843
973
|
async function fetch(leased, eventLimit) {
|
|
@@ -860,7 +990,6 @@ var subscribe = (streams) => store().subscribe(streams);
|
|
|
860
990
|
// src/internal/event-sourcing.ts
|
|
861
991
|
var import_act_patch = require("@rotorsoft/act-patch");
|
|
862
992
|
var import_crypto = require("crypto");
|
|
863
|
-
var logger2 = log();
|
|
864
993
|
async function snap(snapshot) {
|
|
865
994
|
try {
|
|
866
995
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
@@ -875,11 +1004,11 @@ async function snap(snapshot) {
|
|
|
875
1004
|
// IMPORTANT! - state events are committed right after the snapshot event
|
|
876
1005
|
);
|
|
877
1006
|
} catch (error) {
|
|
878
|
-
|
|
1007
|
+
log().error(error);
|
|
879
1008
|
}
|
|
880
1009
|
}
|
|
881
1010
|
async function load(me, stream, callback, asOf) {
|
|
882
|
-
const timeTravel = asOf && (asOf.
|
|
1011
|
+
const timeTravel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
|
|
883
1012
|
const cached = timeTravel ? void 0 : await cache().get(stream);
|
|
884
1013
|
let state2 = cached?.state ?? (me.init ? me.init() : {});
|
|
885
1014
|
let patches = cached?.patches ?? 0;
|
|
@@ -963,7 +1092,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
963
1092
|
reactingTo ? void 0 : expected
|
|
964
1093
|
);
|
|
965
1094
|
} catch (error) {
|
|
966
|
-
if (error
|
|
1095
|
+
if (error instanceof ConcurrencyError) {
|
|
967
1096
|
await cache().invalidate(stream);
|
|
968
1097
|
}
|
|
969
1098
|
throw error;
|
|
@@ -977,241 +1106,56 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
977
1106
|
});
|
|
978
1107
|
const last = snapshots.at(-1);
|
|
979
1108
|
const snapped = me.snap && me.snap(last);
|
|
980
|
-
|
|
1109
|
+
cache().set(stream, {
|
|
981
1110
|
state: last.state,
|
|
982
1111
|
version: last.event.version,
|
|
983
1112
|
event_id: last.event.id,
|
|
984
1113
|
patches: snapped ? 0 : last.patches,
|
|
985
1114
|
snaps: snapped ? last.snaps + 1 : last.snaps
|
|
986
|
-
});
|
|
1115
|
+
}).catch((err) => log().error(err));
|
|
987
1116
|
if (snapped) void snap(last);
|
|
988
1117
|
return snapshots;
|
|
989
1118
|
}
|
|
990
1119
|
|
|
991
|
-
// src/internal/merge.ts
|
|
992
|
-
var import_zod4 = require("zod");
|
|
993
|
-
function baseTypeName(zodType) {
|
|
994
|
-
let t = zodType;
|
|
995
|
-
while (typeof t.unwrap === "function") {
|
|
996
|
-
t = t.unwrap();
|
|
997
|
-
}
|
|
998
|
-
return t.constructor.name;
|
|
999
|
-
}
|
|
1000
|
-
function mergeSchemas(existing, incoming, stateName) {
|
|
1001
|
-
if (existing instanceof import_zod4.ZodObject && incoming instanceof import_zod4.ZodObject) {
|
|
1002
|
-
const existingShape = existing.shape;
|
|
1003
|
-
const incomingShape = incoming.shape;
|
|
1004
|
-
for (const key of Object.keys(incomingShape)) {
|
|
1005
|
-
if (key in existingShape) {
|
|
1006
|
-
const existingBase = baseTypeName(existingShape[key]);
|
|
1007
|
-
const incomingBase = baseTypeName(incomingShape[key]);
|
|
1008
|
-
if (existingBase !== incomingBase) {
|
|
1009
|
-
throw new Error(
|
|
1010
|
-
`Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
|
|
1011
|
-
);
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
return existing.extend(incomingShape);
|
|
1016
|
-
}
|
|
1017
|
-
return existing;
|
|
1018
|
-
}
|
|
1019
|
-
function mergeInits(existing, incoming) {
|
|
1020
|
-
return () => ({ ...existing(), ...incoming() });
|
|
1021
|
-
}
|
|
1022
|
-
function registerState(state2, states, actions, events) {
|
|
1023
|
-
if (states.has(state2.name)) {
|
|
1024
|
-
const existing = states.get(state2.name);
|
|
1025
|
-
for (const name of Object.keys(state2.actions)) {
|
|
1026
|
-
if (existing.actions[name] === state2.actions[name]) continue;
|
|
1027
|
-
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
1028
|
-
}
|
|
1029
|
-
for (const name of Object.keys(state2.events)) {
|
|
1030
|
-
if (existing.events[name] === state2.events[name]) continue;
|
|
1031
|
-
if (existing.events[name]) continue;
|
|
1032
|
-
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
1033
|
-
}
|
|
1034
|
-
const mergedPatch = { ...existing.patch };
|
|
1035
|
-
for (const name of Object.keys(state2.patch)) {
|
|
1036
|
-
const existingP = existing.patch[name];
|
|
1037
|
-
const incomingP = state2.patch[name];
|
|
1038
|
-
if (!existingP) {
|
|
1039
|
-
mergedPatch[name] = incomingP;
|
|
1040
|
-
} else {
|
|
1041
|
-
const existingIsDefault = existingP._passthrough;
|
|
1042
|
-
const incomingIsDefault = incomingP._passthrough;
|
|
1043
|
-
if (!existingIsDefault && !incomingIsDefault && existingP !== incomingP) {
|
|
1044
|
-
throw new Error(
|
|
1045
|
-
`Duplicate custom patch for event "${name}" in state "${state2.name}"`
|
|
1046
|
-
);
|
|
1047
|
-
}
|
|
1048
|
-
if (existingIsDefault && !incomingIsDefault) {
|
|
1049
|
-
mergedPatch[name] = incomingP;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
const merged = {
|
|
1054
|
-
...existing,
|
|
1055
|
-
state: mergeSchemas(existing.state, state2.state, state2.name),
|
|
1056
|
-
init: mergeInits(existing.init, state2.init),
|
|
1057
|
-
events: { ...existing.events, ...state2.events },
|
|
1058
|
-
actions: { ...existing.actions, ...state2.actions },
|
|
1059
|
-
patch: mergedPatch,
|
|
1060
|
-
on: { ...existing.on, ...state2.on },
|
|
1061
|
-
given: { ...existing.given, ...state2.given },
|
|
1062
|
-
snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
|
|
1063
|
-
throw new Error(
|
|
1064
|
-
`Duplicate snap strategy for state "${state2.name}"`
|
|
1065
|
-
);
|
|
1066
|
-
})() : state2.snap || existing.snap
|
|
1067
|
-
};
|
|
1068
|
-
states.set(state2.name, merged);
|
|
1069
|
-
for (const name of Object.keys(merged.actions)) {
|
|
1070
|
-
actions[name] = merged;
|
|
1071
|
-
}
|
|
1072
|
-
for (const name of Object.keys(state2.events)) {
|
|
1073
|
-
if (events[name]) continue;
|
|
1074
|
-
events[name] = {
|
|
1075
|
-
schema: state2.events[name],
|
|
1076
|
-
reactions: /* @__PURE__ */ new Map()
|
|
1077
|
-
};
|
|
1078
|
-
}
|
|
1079
|
-
} else {
|
|
1080
|
-
states.set(state2.name, state2);
|
|
1081
|
-
for (const name of Object.keys(state2.actions)) {
|
|
1082
|
-
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
1083
|
-
actions[name] = state2;
|
|
1084
|
-
}
|
|
1085
|
-
for (const name of Object.keys(state2.events)) {
|
|
1086
|
-
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
1087
|
-
events[name] = {
|
|
1088
|
-
schema: state2.events[name],
|
|
1089
|
-
reactions: /* @__PURE__ */ new Map()
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
function mergeProjection(proj, events) {
|
|
1095
|
-
for (const eventName of Object.keys(proj.events)) {
|
|
1096
|
-
const projRegister = proj.events[eventName];
|
|
1097
|
-
const existing = events[eventName];
|
|
1098
|
-
if (!existing) {
|
|
1099
|
-
events[eventName] = {
|
|
1100
|
-
schema: projRegister.schema,
|
|
1101
|
-
reactions: new Map(projRegister.reactions)
|
|
1102
|
-
};
|
|
1103
|
-
} else {
|
|
1104
|
-
for (const [name, reaction] of projRegister.reactions) {
|
|
1105
|
-
let key = name;
|
|
1106
|
-
while (existing.reactions.has(key)) key = `${key}_p`;
|
|
1107
|
-
existing.reactions.set(key, reaction);
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
var _this_ = ({ stream }) => ({
|
|
1113
|
-
source: stream,
|
|
1114
|
-
target: stream
|
|
1115
|
-
});
|
|
1116
|
-
|
|
1117
1120
|
// src/internal/tracing.ts
|
|
1118
|
-
var
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
logger3.trace(`\u{1F7E2} load ${stream}${asOf ? " (as-of)" : ""}`);
|
|
1127
|
-
return inner(me, stream, callback, asOf);
|
|
1128
|
-
};
|
|
1129
|
-
var withActionTrace = (inner) => async (me, action2, target, payload, reactingTo, skipValidation) => {
|
|
1130
|
-
logger3.trace(payload, `\u{1F535} ${target.stream}.${action2}`);
|
|
1131
|
-
const snapshots = await inner(
|
|
1132
|
-
me,
|
|
1133
|
-
action2,
|
|
1134
|
-
target,
|
|
1135
|
-
payload,
|
|
1136
|
-
reactingTo,
|
|
1137
|
-
skipValidation
|
|
1138
|
-
);
|
|
1139
|
-
const committed = snapshots.filter((s) => s.event);
|
|
1140
|
-
if (committed.length) {
|
|
1141
|
-
logger3.trace(
|
|
1142
|
-
committed.map((s) => s.event.data),
|
|
1143
|
-
`\u{1F534} commit ${target.stream}.${committed.map((s) => s.event.name).join(", ")}`
|
|
1144
|
-
);
|
|
1145
|
-
}
|
|
1146
|
-
return snapshots;
|
|
1147
|
-
};
|
|
1148
|
-
function buildEs(level) {
|
|
1149
|
-
if (level !== "trace") {
|
|
1121
|
+
var traced = (inner, exit, entry) => (async (...args) => {
|
|
1122
|
+
entry?.(...args);
|
|
1123
|
+
const result = await inner(...args);
|
|
1124
|
+
exit?.(result, ...args);
|
|
1125
|
+
return result;
|
|
1126
|
+
});
|
|
1127
|
+
function buildEs(logger2) {
|
|
1128
|
+
if (logger2.level !== "trace") {
|
|
1150
1129
|
return { snap, load, action };
|
|
1151
1130
|
}
|
|
1152
1131
|
return {
|
|
1153
|
-
snap:
|
|
1154
|
-
|
|
1155
|
-
|
|
1132
|
+
snap: traced(snap, void 0, (snapshot) => {
|
|
1133
|
+
logger2.trace(
|
|
1134
|
+
`\u{1F7E0} snap ${snapshot.event.stream}@${snapshot.event.version}`
|
|
1135
|
+
);
|
|
1136
|
+
}),
|
|
1137
|
+
load: traced(load, void 0, (_me, stream, _cb, asOf) => {
|
|
1138
|
+
logger2.trace(`\u{1F7E2} load ${stream}${asOf ? " (as-of)" : ""}`);
|
|
1139
|
+
}),
|
|
1140
|
+
action: traced(
|
|
1141
|
+
action,
|
|
1142
|
+
(snapshots, _me, _action, target) => {
|
|
1143
|
+
const committed = snapshots.filter((s) => s.event);
|
|
1144
|
+
if (committed.length) {
|
|
1145
|
+
logger2.trace(
|
|
1146
|
+
committed.map((s) => s.event.data),
|
|
1147
|
+
`\u{1F534} commit ${target.stream}.${committed.map((s) => s.event.name).join(", ")}`
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
},
|
|
1151
|
+
(_me, action2, target, payload) => {
|
|
1152
|
+
logger2.trace(payload, `\u{1F535} ${target.stream}.${action2}`);
|
|
1153
|
+
}
|
|
1154
|
+
)
|
|
1156
1155
|
};
|
|
1157
1156
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
if (leased.length) {
|
|
1161
|
-
const data = Object.fromEntries(
|
|
1162
|
-
leased.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1163
|
-
);
|
|
1164
|
-
logger3.trace(data, ">> lease");
|
|
1165
|
-
}
|
|
1166
|
-
return leased;
|
|
1167
|
-
};
|
|
1168
|
-
var withFetchTrace = (inner) => async (leased, eventLimit) => {
|
|
1169
|
-
const fetched = await inner(leased, eventLimit);
|
|
1170
|
-
const data = Object.fromEntries(
|
|
1171
|
-
fetched.map(({ stream, source, events }) => {
|
|
1172
|
-
const key = source ? `${stream}<-${source}` : stream;
|
|
1173
|
-
const value = Object.fromEntries(
|
|
1174
|
-
events.map(({ id, stream: stream2, name }) => [id, { [stream2]: name }])
|
|
1175
|
-
);
|
|
1176
|
-
return [key, value];
|
|
1177
|
-
})
|
|
1178
|
-
);
|
|
1179
|
-
logger3.trace(data, ">> fetch");
|
|
1180
|
-
return fetched;
|
|
1181
|
-
};
|
|
1182
|
-
var withAckTrace = (inner) => async (leases) => {
|
|
1183
|
-
const acked = await inner(leases);
|
|
1184
|
-
if (acked.length) {
|
|
1185
|
-
const data = Object.fromEntries(
|
|
1186
|
-
acked.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1187
|
-
);
|
|
1188
|
-
logger3.trace(data, ">> ack");
|
|
1189
|
-
}
|
|
1190
|
-
return acked;
|
|
1191
|
-
};
|
|
1192
|
-
var withBlockTrace = (inner) => async (leases) => {
|
|
1193
|
-
const blocked = await inner(leases);
|
|
1194
|
-
if (blocked.length) {
|
|
1195
|
-
const data = Object.fromEntries(
|
|
1196
|
-
blocked.map(({ stream, at, retry, error }) => [
|
|
1197
|
-
stream,
|
|
1198
|
-
{ at, retry, error }
|
|
1199
|
-
])
|
|
1200
|
-
);
|
|
1201
|
-
logger3.trace(data, ">> block");
|
|
1202
|
-
}
|
|
1203
|
-
return blocked;
|
|
1204
|
-
};
|
|
1205
|
-
var withSubscribeTrace = (inner) => async (streams) => {
|
|
1206
|
-
const result = await inner(streams);
|
|
1207
|
-
if (result.subscribed) {
|
|
1208
|
-
const data = streams.map(({ stream }) => stream).join(" ");
|
|
1209
|
-
logger3.trace(`>> correlate ${data}`);
|
|
1210
|
-
}
|
|
1211
|
-
return result;
|
|
1212
|
-
};
|
|
1213
|
-
function buildDrain(level) {
|
|
1214
|
-
if (level !== "trace") {
|
|
1157
|
+
function buildDrain(logger2) {
|
|
1158
|
+
if (logger2.level !== "trace") {
|
|
1215
1159
|
return {
|
|
1216
1160
|
claim,
|
|
1217
1161
|
fetch,
|
|
@@ -1221,24 +1165,62 @@ function buildDrain(level) {
|
|
|
1221
1165
|
};
|
|
1222
1166
|
}
|
|
1223
1167
|
return {
|
|
1224
|
-
claim:
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1168
|
+
claim: traced(claim, (leased) => {
|
|
1169
|
+
if (leased.length) {
|
|
1170
|
+
const data = Object.fromEntries(
|
|
1171
|
+
leased.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1172
|
+
);
|
|
1173
|
+
logger2.trace(data, ">> lease");
|
|
1174
|
+
}
|
|
1175
|
+
}),
|
|
1176
|
+
fetch: traced(fetch, (fetched) => {
|
|
1177
|
+
const data = Object.fromEntries(
|
|
1178
|
+
fetched.map(({ stream, source, events }) => {
|
|
1179
|
+
const key = source ? `${stream}<-${source}` : stream;
|
|
1180
|
+
const value = Object.fromEntries(
|
|
1181
|
+
events.map(({ id, stream: stream2, name }) => [id, { [stream2]: name }])
|
|
1182
|
+
);
|
|
1183
|
+
return [key, value];
|
|
1184
|
+
})
|
|
1185
|
+
);
|
|
1186
|
+
logger2.trace(data, ">> fetch");
|
|
1187
|
+
}),
|
|
1188
|
+
ack: traced(ack, (acked) => {
|
|
1189
|
+
if (acked.length) {
|
|
1190
|
+
const data = Object.fromEntries(
|
|
1191
|
+
acked.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1192
|
+
);
|
|
1193
|
+
logger2.trace(data, ">> ack");
|
|
1194
|
+
}
|
|
1195
|
+
}),
|
|
1196
|
+
block: traced(block, (blocked) => {
|
|
1197
|
+
if (blocked.length) {
|
|
1198
|
+
const data = Object.fromEntries(
|
|
1199
|
+
blocked.map(({ stream, at, retry, error }) => [
|
|
1200
|
+
stream,
|
|
1201
|
+
{ at, retry, error }
|
|
1202
|
+
])
|
|
1203
|
+
);
|
|
1204
|
+
logger2.trace(data, ">> block");
|
|
1205
|
+
}
|
|
1206
|
+
}),
|
|
1207
|
+
subscribe: traced(subscribe, (result, streams) => {
|
|
1208
|
+
if (result.subscribed) {
|
|
1209
|
+
const data = streams.map(({ stream }) => stream).join(" ");
|
|
1210
|
+
logger2.trace(`>> correlate ${data}`);
|
|
1211
|
+
}
|
|
1212
|
+
})
|
|
1229
1213
|
};
|
|
1230
1214
|
}
|
|
1231
1215
|
|
|
1232
1216
|
// src/act.ts
|
|
1233
|
-
var logger4 = log();
|
|
1234
1217
|
var Act = class {
|
|
1235
1218
|
constructor(registry, _states = /* @__PURE__ */ new Map(), batchHandlers = /* @__PURE__ */ new Map()) {
|
|
1236
1219
|
this.registry = registry;
|
|
1237
1220
|
this._states = _states;
|
|
1238
1221
|
this._batch_handlers = batchHandlers;
|
|
1239
|
-
|
|
1240
|
-
this.
|
|
1241
|
-
this._cd = buildDrain(level);
|
|
1222
|
+
this._es = buildEs(this._logger);
|
|
1223
|
+
this._cd = buildDrain(this._logger);
|
|
1242
1224
|
const statics = [];
|
|
1243
1225
|
for (const [name, register] of Object.entries(this.registry.events)) {
|
|
1244
1226
|
if (register.reactions.size > 0) {
|
|
@@ -1302,6 +1284,8 @@ var Act = class {
|
|
|
1302
1284
|
_es;
|
|
1303
1285
|
/** Correlate/drain pipeline ops, optionally wrapped with trace decorators */
|
|
1304
1286
|
_cd;
|
|
1287
|
+
/** Logger resolved at construction time (after user port configuration) */
|
|
1288
|
+
_logger = log();
|
|
1305
1289
|
/**
|
|
1306
1290
|
* Executes an action on a state instance, committing resulting events.
|
|
1307
1291
|
*
|
|
@@ -1523,7 +1507,7 @@ var Act = class {
|
|
|
1523
1507
|
if (payloads.length === 0) return { lease, handled: 0, at: lease.at };
|
|
1524
1508
|
const stream = lease.stream;
|
|
1525
1509
|
let at = payloads.at(0).event.id, handled = 0;
|
|
1526
|
-
lease.retry > 0 &&
|
|
1510
|
+
lease.retry > 0 && this._logger.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
|
|
1527
1511
|
const doAction = this.do.bind(this);
|
|
1528
1512
|
const scopedApp = {
|
|
1529
1513
|
do: doAction,
|
|
@@ -1545,9 +1529,11 @@ var Act = class {
|
|
|
1545
1529
|
at = event.id;
|
|
1546
1530
|
handled++;
|
|
1547
1531
|
} catch (error) {
|
|
1548
|
-
|
|
1532
|
+
this._logger.error(error);
|
|
1549
1533
|
const block2 = lease.retry >= options.maxRetries && options.blockOnError;
|
|
1550
|
-
block2 &&
|
|
1534
|
+
block2 && this._logger.error(
|
|
1535
|
+
`Blocking ${stream} after ${lease.retry} retries.`
|
|
1536
|
+
);
|
|
1551
1537
|
return {
|
|
1552
1538
|
lease,
|
|
1553
1539
|
handled,
|
|
@@ -1577,15 +1563,17 @@ var Act = class {
|
|
|
1577
1563
|
const stream = lease.stream;
|
|
1578
1564
|
const events = payloads.map((p) => p.event);
|
|
1579
1565
|
const at = events.at(-1).id;
|
|
1580
|
-
lease.retry > 0 &&
|
|
1566
|
+
lease.retry > 0 && this._logger.warn(
|
|
1567
|
+
`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`
|
|
1568
|
+
);
|
|
1581
1569
|
try {
|
|
1582
1570
|
await batchHandler(events, stream);
|
|
1583
1571
|
return { lease, handled: events.length, at };
|
|
1584
1572
|
} catch (error) {
|
|
1585
|
-
|
|
1573
|
+
this._logger.error(error);
|
|
1586
1574
|
const { options } = payloads[0];
|
|
1587
1575
|
const block2 = lease.retry >= options.maxRetries && options.blockOnError;
|
|
1588
|
-
block2 &&
|
|
1576
|
+
block2 && this._logger.error(`Blocking ${stream} after ${lease.retry} retries.`);
|
|
1589
1577
|
return {
|
|
1590
1578
|
lease,
|
|
1591
1579
|
handled: 0,
|
|
@@ -1711,7 +1699,7 @@ var Act = class {
|
|
|
1711
1699
|
this._needs_drain = false;
|
|
1712
1700
|
return result;
|
|
1713
1701
|
} catch (error) {
|
|
1714
|
-
|
|
1702
|
+
this._logger.error(error);
|
|
1715
1703
|
} finally {
|
|
1716
1704
|
this._drain_locked = false;
|
|
1717
1705
|
}
|
|
@@ -2191,7 +2179,7 @@ var Act = class {
|
|
|
2191
2179
|
if (!made_progress) break;
|
|
2192
2180
|
}
|
|
2193
2181
|
if (lastDrain) this.emit("settled", lastDrain);
|
|
2194
|
-
})().catch((err) =>
|
|
2182
|
+
})().catch((err) => this._logger.error(err)).finally(() => {
|
|
2195
2183
|
this._settling = false;
|
|
2196
2184
|
});
|
|
2197
2185
|
}, debounceMs);
|
|
@@ -2438,8 +2426,9 @@ function state(entry) {
|
|
|
2438
2426
|
emits(events) {
|
|
2439
2427
|
const defaultPatch = Object.fromEntries(
|
|
2440
2428
|
Object.keys(events).map((k) => {
|
|
2441
|
-
const fn = ({ data }) => data
|
|
2442
|
-
|
|
2429
|
+
const fn = Object.assign(({ data }) => data, {
|
|
2430
|
+
_passthrough: true
|
|
2431
|
+
});
|
|
2443
2432
|
return [k, fn];
|
|
2444
2433
|
})
|
|
2445
2434
|
);
|