@rotorsoft/act 0.32.2 → 0.32.4
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-builder.d.ts.map +1 -1
- package/dist/@types/act.d.ts +13 -0
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/config.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/tracing.d.ts +9 -2
- package/dist/@types/internal/tracing.d.ts.map +1 -1
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/utils.d.ts.map +1 -1
- package/dist/index.cjs +143 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +144 -80
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-sourcing.d.ts","sourceRoot":"","sources":["../../../src/internal/event-sourcing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,OAAO,KAAK,EACV,IAAI,EACJ,SAAS,EAGT,MAAM,EACN,OAAO,EACP,QAAQ,EACR,KAAK,EACL,MAAM,EACP,MAAM,mBAAmB,CAAC;AAG3B,gBAAgB;AAChB,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,MAAM,EAAE,OAAO,MAAM,CAAC;CACvB;AAED;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAsB,IAAI,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,SAAS,OAAO,EACvE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,IAAI,CACxB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,OAAO,EACvB,QAAQ,SAAS,OAAO,EAExB,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EACxD,IAAI,CAAC,EAAE,IAAI,GACV,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"event-sourcing.d.ts","sourceRoot":"","sources":["../../../src/internal/event-sourcing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,OAAO,KAAK,EACV,IAAI,EACJ,SAAS,EAGT,MAAM,EACN,OAAO,EACP,QAAQ,EACR,KAAK,EACL,MAAM,EACP,MAAM,mBAAmB,CAAC;AAG3B,gBAAgB;AAChB,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,MAAM,EAAE,OAAO,MAAM,CAAC;CACvB;AAED;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAsB,IAAI,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,SAAS,OAAO,EACvE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,IAAI,CACxB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,OAAO,EACvB,QAAQ,SAAS,OAAO,EAExB,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EACxD,IAAI,CAAC,EAAE,IAAI,GACV,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqCpC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,MAAM,CAC1B,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,OAAO,EACvB,QAAQ,SAAS,OAAO,EACxB,IAAI,SAAS,MAAM,QAAQ,EAE3B,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EACpC,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EACjC,UAAU,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,EAC9C,cAAc,UAAQ,GACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CA+GtC"}
|
|
@@ -8,8 +8,15 @@
|
|
|
8
8
|
* at well-defined moments — entry points for {@link "event-sourcing"} (`load`,
|
|
9
9
|
* `snap`, `action`) and exit points for the {@link "drain"} pipeline (`claim`,
|
|
10
10
|
* `fetch`, `ack`, `block`, `subscribe`). `action` carries both an entry log
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* and a post-commit log to preserve the diagnostic value of the historical
|
|
12
|
+
* mid-function trace points.
|
|
13
|
+
*
|
|
14
|
+
* Output styles:
|
|
15
|
+
* - **Pretty mode** (`config().env !== "production"`) — event-sourcing logs
|
|
16
|
+
* show only the colored target body (color carries the operation/phase),
|
|
17
|
+
* drain logs keep a colored caption.
|
|
18
|
+
* - **Plain mode** (production / log aggregators) — every log gets a textual
|
|
19
|
+
* prefix; event-sourcing uses `caption: body`, drain uses `caption body`.
|
|
13
20
|
*
|
|
14
21
|
* The two factories — {@link buildEs} and {@link buildDrain} — let the
|
|
15
22
|
* orchestrator choose bare or traced variants once at `.build()` time based
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../../src/internal/tracing.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../../src/internal/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAqDjD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CA0C7C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,SAAS,OAAO,EAChD,MAAM,EAAE,MAAM,GACb,QAAQ,CAAC,OAAO,CAAC,CAyDnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/ports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAI5D,OAAO,KAAK,EACV,KAAK,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,KAAK,EACN,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;GAaG;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS,4BAA6B,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAMlD;;;GAGG;AACH,KAAK,QAAQ,CAAC,IAAI,SAAS,UAAU,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC;AAKlE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,IAAI,CAAC,IAAI,SAAS,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,IACnD,UAAU,IAAI,KAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/ports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAI5D,OAAO,KAAK,EACV,KAAK,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,KAAK,EACN,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;GAaG;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS,4BAA6B,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAMlD;;;GAGG;AACH,KAAK,QAAQ,CAAC,IAAI,SAAS,UAAU,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC;AAKlE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,IAAI,CAAC,IAAI,SAAS,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,IACnD,UAAU,IAAI,KAAG,IAAI,CAWvC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,GAAG,0EASd,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,KAAK,wCAEhB,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,KAAK,wCAEhB,CAAC;AASH;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE,QAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAe3E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CACrB,QAAQ,CAAC,EAAE,QAAQ,GAClB,CAAC,IAAI,CAAC,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAGpC;AAMD;;;;GAIG;AACH,eAAO,MAAM,UAAU,iBAAiB,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAiB,MAAM,KAAK,CAAC;AAI5D;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,QAAQ,MAAM,EACd,SAAS,QAAQ,CAAC,CAAC,CAAC,EACpB,SAAS,OAAO,CAAC,CAAC,CAAC,KAClB,QAAQ,CAAC,CAAC,CASZ,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwHG;AACH,eAAO,MAAM,MAAM,GACjB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAEjC,QAAQ,QAAQ,CAAC,CAAC,CAAC,EACnB,QAAQ,OAAO,CAAC,CAAC,CAAC,EAClB,SAAS,QAAQ,CAAC,CAAC,CAAC,KACnB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAGhB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuFG;AACH,wBAAsB,KAAK,CAAC,EAAE,CAAC,EAAE,MAAM,oBAEtC"}
|
package/dist/index.cjs
CHANGED
|
@@ -345,12 +345,19 @@ var BaseSchema = PackageSchema.extend({
|
|
|
345
345
|
});
|
|
346
346
|
var { NODE_ENV, LOG_LEVEL, LOG_SINGLE_LINE, SLEEP_MS } = process.env;
|
|
347
347
|
var env = NODE_ENV || "development";
|
|
348
|
-
var logLevel = LOG_LEVEL || (NODE_ENV === "test" ? "
|
|
348
|
+
var logLevel = LOG_LEVEL || (NODE_ENV === "test" ? "fatal" : NODE_ENV === "production" ? "info" : "trace");
|
|
349
349
|
var logSingleLine = (LOG_SINGLE_LINE || "true") === "true";
|
|
350
|
-
var sleepMs = parseInt(NODE_ENV === "test" ? "0" : SLEEP_MS ?? "100");
|
|
350
|
+
var sleepMs = parseInt(NODE_ENV === "test" ? "0" : SLEEP_MS ?? "100", 10);
|
|
351
351
|
var pkg = getPackage();
|
|
352
|
+
var _validated;
|
|
352
353
|
var config = () => {
|
|
353
|
-
|
|
354
|
+
if (!_validated) {
|
|
355
|
+
_validated = extend(
|
|
356
|
+
{ ...pkg, env, logLevel, logSingleLine, sleepMs },
|
|
357
|
+
BaseSchema
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return _validated;
|
|
354
361
|
};
|
|
355
362
|
|
|
356
363
|
// src/utils.ts
|
|
@@ -358,19 +365,15 @@ var validate = (target, payload, schema) => {
|
|
|
358
365
|
try {
|
|
359
366
|
return schema ? schema.parse(payload) : payload;
|
|
360
367
|
} catch (error) {
|
|
361
|
-
if (error instanceof
|
|
362
|
-
throw new ValidationError(
|
|
363
|
-
target,
|
|
364
|
-
payload,
|
|
365
|
-
(0, import_zod3.prettifyError)(error)
|
|
366
|
-
);
|
|
368
|
+
if (error instanceof import_zod3.ZodError) {
|
|
369
|
+
throw new ValidationError(target, payload, (0, import_zod3.prettifyError)(error));
|
|
367
370
|
}
|
|
368
371
|
throw new ValidationError(target, payload, error);
|
|
369
372
|
}
|
|
370
373
|
};
|
|
371
374
|
var extend = (source, schema, target) => {
|
|
372
375
|
const value = validate("config", source, schema);
|
|
373
|
-
return
|
|
376
|
+
return { ...target, ...value };
|
|
374
377
|
};
|
|
375
378
|
async function sleep(ms) {
|
|
376
379
|
return new Promise((resolve) => setTimeout(resolve, ms ?? config().sleepMs));
|
|
@@ -777,7 +780,7 @@ function port(injector) {
|
|
|
777
780
|
if (!adapters.has(injector.name)) {
|
|
778
781
|
const injected = injector(adapter);
|
|
779
782
|
adapters.set(injector.name, injected);
|
|
780
|
-
|
|
783
|
+
log().info(`[act] + ${injector.name}:${injected.constructor.name}`);
|
|
781
784
|
}
|
|
782
785
|
return adapters.get(injector.name);
|
|
783
786
|
};
|
|
@@ -798,13 +801,13 @@ var cache = port(function cache2(adapter) {
|
|
|
798
801
|
var disposers = [];
|
|
799
802
|
async function disposeAndExit(code = "EXIT") {
|
|
800
803
|
if (code === "ERROR" && config().env === "production") return;
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
})
|
|
807
|
-
|
|
804
|
+
for (const disposer of [...disposers].reverse()) {
|
|
805
|
+
await disposer();
|
|
806
|
+
}
|
|
807
|
+
for (const adapter of [...adapters.values()].reverse()) {
|
|
808
|
+
await adapter.dispose();
|
|
809
|
+
log().info(`[act] - ${adapter.constructor.name}`);
|
|
810
|
+
}
|
|
808
811
|
adapters.clear();
|
|
809
812
|
config().env !== "test" && process.exit(code === "ERROR" ? 1 : 0);
|
|
810
813
|
}
|
|
@@ -816,21 +819,20 @@ var SNAP_EVENT = "__snapshot__";
|
|
|
816
819
|
var TOMBSTONE_EVENT = "__tombstone__";
|
|
817
820
|
|
|
818
821
|
// src/signals.ts
|
|
819
|
-
var logger = log();
|
|
820
822
|
process.once("SIGINT", async (arg) => {
|
|
821
|
-
|
|
823
|
+
log().info(arg, "SIGINT");
|
|
822
824
|
await disposeAndExit("EXIT");
|
|
823
825
|
});
|
|
824
826
|
process.once("SIGTERM", async (arg) => {
|
|
825
|
-
|
|
827
|
+
log().info(arg, "SIGTERM");
|
|
826
828
|
await disposeAndExit("EXIT");
|
|
827
829
|
});
|
|
828
830
|
process.once("uncaughtException", async (arg) => {
|
|
829
|
-
|
|
831
|
+
log().error(arg, "Uncaught Exception");
|
|
830
832
|
await disposeAndExit("ERROR");
|
|
831
833
|
});
|
|
832
834
|
process.once("unhandledRejection", async (arg) => {
|
|
833
|
-
|
|
835
|
+
log().error(arg, "Unhandled Rejection");
|
|
834
836
|
await disposeAndExit("ERROR");
|
|
835
837
|
});
|
|
836
838
|
|
|
@@ -1024,6 +1026,10 @@ async function load(me, stream, callback, asOf) {
|
|
|
1024
1026
|
} else if (me.patch[e.name]) {
|
|
1025
1027
|
state2 = (0, import_act_patch.patch)(state2, me.patch[e.name](event, state2));
|
|
1026
1028
|
patches++;
|
|
1029
|
+
} else if (e.name !== TOMBSTONE_EVENT) {
|
|
1030
|
+
log().warn(
|
|
1031
|
+
`Skipping unknown event "${String(e.name)}" on stream "${stream}" (id=${e.id}) \u2014 no reducer in state "${me.name}"`
|
|
1032
|
+
);
|
|
1027
1033
|
}
|
|
1028
1034
|
callback && callback({ event, state: state2, patches, snaps });
|
|
1029
1035
|
},
|
|
@@ -1118,44 +1124,69 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1118
1124
|
}
|
|
1119
1125
|
|
|
1120
1126
|
// src/internal/tracing.ts
|
|
1127
|
+
var PRETTY = config().env !== "production";
|
|
1128
|
+
var C_BLUE = "\x1B[38;5;39m";
|
|
1129
|
+
var C_ORANGE = "\x1B[38;5;208m";
|
|
1130
|
+
var C_GREEN = "\x1B[38;5;42m";
|
|
1131
|
+
var C_MAGENTA = "\x1B[38;5;165m";
|
|
1132
|
+
var C_DRAIN = "\x1B[38;5;244m";
|
|
1133
|
+
var C_RESET = "\x1B[0m";
|
|
1134
|
+
var es_caption = (caption, color, body) => PRETTY ? `${color}${body}${C_RESET}` : `${caption}: ${body}`;
|
|
1135
|
+
var drain_caption = (caption) => {
|
|
1136
|
+
const tag = `>> ${caption}`;
|
|
1137
|
+
return PRETTY ? `${C_DRAIN}${tag}${C_RESET}` : tag;
|
|
1138
|
+
};
|
|
1121
1139
|
var traced = (inner, exit, entry) => (async (...args) => {
|
|
1122
1140
|
entry?.(...args);
|
|
1123
1141
|
const result = await inner(...args);
|
|
1124
1142
|
exit?.(result, ...args);
|
|
1125
1143
|
return result;
|
|
1126
1144
|
});
|
|
1127
|
-
function buildEs(
|
|
1128
|
-
if (
|
|
1145
|
+
function buildEs(logger) {
|
|
1146
|
+
if (logger.level !== "trace") {
|
|
1129
1147
|
return { snap, load, action };
|
|
1130
1148
|
}
|
|
1131
1149
|
return {
|
|
1132
1150
|
snap: traced(snap, void 0, (snapshot) => {
|
|
1133
|
-
|
|
1134
|
-
|
|
1151
|
+
logger.trace(
|
|
1152
|
+
es_caption(
|
|
1153
|
+
"snap",
|
|
1154
|
+
C_MAGENTA,
|
|
1155
|
+
`${snapshot.event.stream}@${snapshot.event.version}`
|
|
1156
|
+
)
|
|
1135
1157
|
);
|
|
1136
1158
|
}),
|
|
1137
1159
|
load: traced(load, void 0, (_me, stream, _cb, asOf) => {
|
|
1138
|
-
|
|
1160
|
+
logger.trace(
|
|
1161
|
+
es_caption("load", C_GREEN, `${stream}${asOf ? " (as-of)" : ""}`)
|
|
1162
|
+
);
|
|
1139
1163
|
}),
|
|
1140
1164
|
action: traced(
|
|
1141
1165
|
action,
|
|
1142
1166
|
(snapshots, _me, _action, target) => {
|
|
1143
1167
|
const committed = snapshots.filter((s) => s.event);
|
|
1144
1168
|
if (committed.length) {
|
|
1145
|
-
|
|
1169
|
+
logger.trace(
|
|
1146
1170
|
committed.map((s) => s.event.data),
|
|
1147
|
-
|
|
1171
|
+
es_caption(
|
|
1172
|
+
"committed",
|
|
1173
|
+
C_ORANGE,
|
|
1174
|
+
`${target.stream}.${committed.map((s) => s.event.name).join(", ")}`
|
|
1175
|
+
)
|
|
1148
1176
|
);
|
|
1149
1177
|
}
|
|
1150
1178
|
},
|
|
1151
1179
|
(_me, action2, target, payload) => {
|
|
1152
|
-
|
|
1180
|
+
logger.trace(
|
|
1181
|
+
payload,
|
|
1182
|
+
es_caption("action", C_BLUE, `${target.stream}.${action2}`)
|
|
1183
|
+
);
|
|
1153
1184
|
}
|
|
1154
1185
|
)
|
|
1155
1186
|
};
|
|
1156
1187
|
}
|
|
1157
|
-
function buildDrain(
|
|
1158
|
-
if (
|
|
1188
|
+
function buildDrain(logger) {
|
|
1189
|
+
if (logger.level !== "trace") {
|
|
1159
1190
|
return {
|
|
1160
1191
|
claim,
|
|
1161
1192
|
fetch,
|
|
@@ -1170,7 +1201,7 @@ function buildDrain(logger2) {
|
|
|
1170
1201
|
const data = Object.fromEntries(
|
|
1171
1202
|
leased.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1172
1203
|
);
|
|
1173
|
-
|
|
1204
|
+
logger.trace(data, drain_caption("claimed"));
|
|
1174
1205
|
}
|
|
1175
1206
|
}),
|
|
1176
1207
|
fetch: traced(fetch, (fetched) => {
|
|
@@ -1183,14 +1214,14 @@ function buildDrain(logger2) {
|
|
|
1183
1214
|
return [key, value];
|
|
1184
1215
|
})
|
|
1185
1216
|
);
|
|
1186
|
-
|
|
1217
|
+
logger.trace(data, drain_caption("fetched"));
|
|
1187
1218
|
}),
|
|
1188
1219
|
ack: traced(ack, (acked) => {
|
|
1189
1220
|
if (acked.length) {
|
|
1190
1221
|
const data = Object.fromEntries(
|
|
1191
1222
|
acked.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
1192
1223
|
);
|
|
1193
|
-
|
|
1224
|
+
logger.trace(data, drain_caption("acked"));
|
|
1194
1225
|
}
|
|
1195
1226
|
}),
|
|
1196
1227
|
block: traced(block, (blocked) => {
|
|
@@ -1201,13 +1232,13 @@ function buildDrain(logger2) {
|
|
|
1201
1232
|
{ at, retry, error }
|
|
1202
1233
|
])
|
|
1203
1234
|
);
|
|
1204
|
-
|
|
1235
|
+
logger.trace(data, drain_caption("blocked"));
|
|
1205
1236
|
}
|
|
1206
1237
|
}),
|
|
1207
1238
|
subscribe: traced(subscribe, (result, streams) => {
|
|
1208
1239
|
if (result.subscribed) {
|
|
1209
1240
|
const data = streams.map(({ stream }) => stream).join(" ");
|
|
1210
|
-
|
|
1241
|
+
logger.trace(`${drain_caption("correlated")} ${data}`);
|
|
1211
1242
|
}
|
|
1212
1243
|
})
|
|
1213
1244
|
};
|
|
@@ -1221,7 +1252,7 @@ var Act = class {
|
|
|
1221
1252
|
this._batch_handlers = batchHandlers;
|
|
1222
1253
|
this._es = buildEs(this._logger);
|
|
1223
1254
|
this._cd = buildDrain(this._logger);
|
|
1224
|
-
const statics =
|
|
1255
|
+
const statics = /* @__PURE__ */ new Map();
|
|
1225
1256
|
for (const [name, register] of Object.entries(this.registry.events)) {
|
|
1226
1257
|
if (register.reactions.size > 0) {
|
|
1227
1258
|
this._reactive_events.add(name);
|
|
@@ -1230,14 +1261,18 @@ var Act = class {
|
|
|
1230
1261
|
if (typeof reaction.resolver === "function") {
|
|
1231
1262
|
this._has_dynamic_resolvers = true;
|
|
1232
1263
|
} else {
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
});
|
|
1264
|
+
const { target, source } = reaction.resolver;
|
|
1265
|
+
const key = `${target}|${source ?? ""}`;
|
|
1266
|
+
if (!statics.has(key)) statics.set(key, { stream: target, source });
|
|
1237
1267
|
}
|
|
1238
1268
|
}
|
|
1239
1269
|
}
|
|
1240
|
-
this._static_targets = statics;
|
|
1270
|
+
this._static_targets = [...statics.values()];
|
|
1271
|
+
for (const merged of this._states.values()) {
|
|
1272
|
+
for (const eventName of Object.keys(merged.events)) {
|
|
1273
|
+
this._event_to_state.set(eventName, merged);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1241
1276
|
dispose(() => {
|
|
1242
1277
|
this._emitter.removeAllListeners();
|
|
1243
1278
|
this.stop_correlations();
|
|
@@ -1284,8 +1319,21 @@ var Act = class {
|
|
|
1284
1319
|
_es;
|
|
1285
1320
|
/** Correlate/drain pipeline ops, optionally wrapped with trace decorators */
|
|
1286
1321
|
_cd;
|
|
1322
|
+
/**
|
|
1323
|
+
* Event-name → owning state, computed at build time. The duplicate-event
|
|
1324
|
+
* guard in merge.ts ensures one event name maps to at most one state, so
|
|
1325
|
+
* this lookup is unambiguous. Used by `close()` to pick the right reducer
|
|
1326
|
+
* set when seeding a `restart` snapshot in multi-state apps.
|
|
1327
|
+
*/
|
|
1328
|
+
_event_to_state = /* @__PURE__ */ new Map();
|
|
1287
1329
|
/** Logger resolved at construction time (after user port configuration) */
|
|
1288
1330
|
_logger = log();
|
|
1331
|
+
/** Pre-bound IAct methods reused across drain cycles. Only `do` varies per
|
|
1332
|
+
* payload (it captures the triggering event for reactingTo auto-inject). */
|
|
1333
|
+
_bound_do = this.do.bind(this);
|
|
1334
|
+
_bound_load = this.load.bind(this);
|
|
1335
|
+
_bound_query = this.query.bind(this);
|
|
1336
|
+
_bound_query_array = this.query_array.bind(this);
|
|
1289
1337
|
/**
|
|
1290
1338
|
* Executes an action on a state instance, committing resulting events.
|
|
1291
1339
|
*
|
|
@@ -1508,12 +1556,12 @@ var Act = class {
|
|
|
1508
1556
|
const stream = lease.stream;
|
|
1509
1557
|
let at = payloads.at(0).event.id, handled = 0;
|
|
1510
1558
|
lease.retry > 0 && this._logger.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
|
|
1511
|
-
const doAction = this.
|
|
1559
|
+
const doAction = this._bound_do;
|
|
1512
1560
|
const scopedApp = {
|
|
1513
1561
|
do: doAction,
|
|
1514
|
-
load: this.
|
|
1515
|
-
query: this.
|
|
1516
|
-
query_array: this.
|
|
1562
|
+
load: this._bound_load,
|
|
1563
|
+
query: this._bound_query,
|
|
1564
|
+
query_array: this._bound_query_array
|
|
1517
1565
|
};
|
|
1518
1566
|
for (const payload of payloads) {
|
|
1519
1567
|
const { event, handler, options } = payload;
|
|
@@ -1646,12 +1694,13 @@ var Act = class {
|
|
|
1646
1694
|
return { fetched: [], leased: [], acked: [], blocked: [] };
|
|
1647
1695
|
}
|
|
1648
1696
|
const fetched = await this._cd.fetch(leased, eventLimit);
|
|
1649
|
-
const
|
|
1697
|
+
const fetchMap = /* @__PURE__ */ new Map();
|
|
1650
1698
|
const fetch_window_at = fetched.reduce(
|
|
1651
1699
|
(max, { at, events }) => Math.max(max, events.at(-1)?.id || at),
|
|
1652
1700
|
0
|
|
1653
1701
|
);
|
|
1654
|
-
|
|
1702
|
+
for (const f of fetched) {
|
|
1703
|
+
const { stream, events } = f;
|
|
1655
1704
|
const payloads = events.flatMap((event) => {
|
|
1656
1705
|
const register = this.registry.events[event.name];
|
|
1657
1706
|
if (!register) return [];
|
|
@@ -1660,13 +1709,13 @@ var Act = class {
|
|
|
1660
1709
|
return resolved && resolved.target === stream;
|
|
1661
1710
|
}).map((reaction) => ({ ...reaction, event }));
|
|
1662
1711
|
});
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1712
|
+
fetchMap.set(stream, { fetch: f, payloads });
|
|
1713
|
+
}
|
|
1665
1714
|
const handled = await Promise.all(
|
|
1666
1715
|
leased.map((lease) => {
|
|
1667
|
-
const
|
|
1668
|
-
const at =
|
|
1669
|
-
const payloads =
|
|
1716
|
+
const entry = fetchMap.get(lease.stream);
|
|
1717
|
+
const at = entry?.fetch.events.at(-1)?.id || fetch_window_at;
|
|
1718
|
+
const payloads = entry?.payloads ?? [];
|
|
1670
1719
|
const batchHandler = this._batch_handlers.get(lease.stream);
|
|
1671
1720
|
if (batchHandler && payloads.length > 0) {
|
|
1672
1721
|
return this.handleBatch({ ...lease, at }, payloads, batchHandler);
|
|
@@ -2000,16 +2049,24 @@ var Act = class {
|
|
|
2000
2049
|
streams.map(async (s) => {
|
|
2001
2050
|
let maxId = -1;
|
|
2002
2051
|
let version = -1;
|
|
2052
|
+
let lastEventName;
|
|
2003
2053
|
await store().query(
|
|
2004
2054
|
(e) => {
|
|
2005
|
-
if (e.name
|
|
2055
|
+
if (e.name === TOMBSTONE_EVENT) return;
|
|
2056
|
+
if (maxId === -1) {
|
|
2006
2057
|
maxId = e.id;
|
|
2007
2058
|
version = e.version;
|
|
2008
2059
|
}
|
|
2060
|
+
if (e.name !== SNAP_EVENT && lastEventName === void 0) {
|
|
2061
|
+
lastEventName = e.name;
|
|
2062
|
+
}
|
|
2009
2063
|
},
|
|
2010
|
-
|
|
2064
|
+
// limit: 2 covers the typical snapshot-at-head case (snapshot is
|
|
2065
|
+
// always preceded by the domain event it captured). Streams with
|
|
2066
|
+
// unusual layouts fall back to no-seed via the lookup miss path.
|
|
2067
|
+
{ stream: s, stream_exact: true, backward: true, limit: 2 }
|
|
2011
2068
|
);
|
|
2012
|
-
if (maxId >= 0) streamInfo.set(s, { maxId, version });
|
|
2069
|
+
if (maxId >= 0) streamInfo.set(s, { maxId, version, lastEventName });
|
|
2013
2070
|
})
|
|
2014
2071
|
);
|
|
2015
2072
|
const skipped = [];
|
|
@@ -2018,16 +2075,14 @@ var Act = class {
|
|
|
2018
2075
|
safe = [...streamInfo.keys()];
|
|
2019
2076
|
} else {
|
|
2020
2077
|
const pendingSet = /* @__PURE__ */ new Set();
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
for (const lease of leases) {
|
|
2024
|
-
const sourceRe = lease.source ? RegExp(lease.source) : void 0;
|
|
2078
|
+
await store().query_streams((position) => {
|
|
2079
|
+
const sourceRe = position.source ? RegExp(position.source) : void 0;
|
|
2025
2080
|
for (const [stream, info] of streamInfo) {
|
|
2026
|
-
if ((!sourceRe || sourceRe.test(stream)) &&
|
|
2081
|
+
if ((!sourceRe || sourceRe.test(stream)) && position.at < info.maxId) {
|
|
2027
2082
|
pendingSet.add(stream);
|
|
2028
2083
|
}
|
|
2029
2084
|
}
|
|
2030
|
-
}
|
|
2085
|
+
});
|
|
2031
2086
|
safe = [];
|
|
2032
2087
|
for (const [stream] of streamInfo) {
|
|
2033
2088
|
if (pendingSet.has(stream)) {
|
|
@@ -2067,16 +2122,21 @@ var Act = class {
|
|
|
2067
2122
|
this.emit("closed", result2);
|
|
2068
2123
|
return result2;
|
|
2069
2124
|
}
|
|
2070
|
-
const mergedState = [...this._states.values()][0];
|
|
2071
2125
|
const seedStates = /* @__PURE__ */ new Map();
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2126
|
+
await Promise.all(
|
|
2127
|
+
guarded.filter((s) => targetMap.get(s)?.restart).map(async (stream) => {
|
|
2128
|
+
const lastEventName = streamInfo.get(stream)?.lastEventName;
|
|
2129
|
+
const ownerState = lastEventName ? this._event_to_state.get(lastEventName) : void 0;
|
|
2130
|
+
if (!ownerState) {
|
|
2131
|
+
this._logger.error(
|
|
2132
|
+
`Cannot seed restart for "${stream}": no registered state owns event "${lastEventName ?? "<none>"}". Stream will be tombstoned instead.`
|
|
2133
|
+
);
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
const snap2 = await this._es.load(ownerState, stream);
|
|
2137
|
+
seedStates.set(stream, snap2.state);
|
|
2138
|
+
})
|
|
2139
|
+
);
|
|
2080
2140
|
for (const stream of guarded) {
|
|
2081
2141
|
const archiveFn = targetMap.get(stream)?.archive;
|
|
2082
2142
|
if (archiveFn) await archiveFn();
|
|
@@ -2187,6 +2247,14 @@ var Act = class {
|
|
|
2187
2247
|
};
|
|
2188
2248
|
|
|
2189
2249
|
// src/act-builder.ts
|
|
2250
|
+
function registerBatchHandler(proj, batchHandlers) {
|
|
2251
|
+
if (!proj.batchHandler || !proj.target) return;
|
|
2252
|
+
const existing = batchHandlers.get(proj.target);
|
|
2253
|
+
if (existing && existing !== proj.batchHandler) {
|
|
2254
|
+
throw new Error(`Duplicate batch handler for target "${proj.target}"`);
|
|
2255
|
+
}
|
|
2256
|
+
batchHandlers.set(proj.target, proj.batchHandler);
|
|
2257
|
+
}
|
|
2190
2258
|
function act(states = /* @__PURE__ */ new Map(), registry = {
|
|
2191
2259
|
actions: {},
|
|
2192
2260
|
events: {}
|
|
@@ -2221,9 +2289,7 @@ function act(states = /* @__PURE__ */ new Map(), registry = {
|
|
|
2221
2289
|
},
|
|
2222
2290
|
withProjection: (proj) => {
|
|
2223
2291
|
mergeProjection(proj, registry.events);
|
|
2224
|
-
|
|
2225
|
-
batchHandlers.set(proj.target, proj.batchHandler);
|
|
2226
|
-
}
|
|
2292
|
+
registerBatchHandler(proj, batchHandlers);
|
|
2227
2293
|
return act(
|
|
2228
2294
|
states,
|
|
2229
2295
|
registry,
|
|
@@ -2269,9 +2335,7 @@ function act(states = /* @__PURE__ */ new Map(), registry = {
|
|
|
2269
2335
|
build: () => {
|
|
2270
2336
|
for (const proj of pendingProjections) {
|
|
2271
2337
|
mergeProjection(proj, registry.events);
|
|
2272
|
-
|
|
2273
|
-
batchHandlers.set(proj.target, proj.batchHandler);
|
|
2274
|
-
}
|
|
2338
|
+
registerBatchHandler(proj, batchHandlers);
|
|
2275
2339
|
}
|
|
2276
2340
|
return new Act(
|
|
2277
2341
|
registry,
|