@rotorsoft/act 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/ConsoleLogger.d.ts +39 -0
- package/dist/@types/adapters/ConsoleLogger.d.ts.map +1 -0
- package/dist/@types/adapters/index.d.ts +1 -0
- package/dist/@types/adapters/index.d.ts.map +1 -1
- package/dist/@types/event-sourcing.d.ts.map +1 -1
- package/dist/@types/merge.d.ts.map +1 -1
- package/dist/@types/ports.d.ts +118 -146
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/state-builder.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +28 -0
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/index.cjs +165 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +163 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -3
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
CausationEventSchema: () => CausationEventSchema,
|
|
36
36
|
CommittedMetaSchema: () => CommittedMetaSchema,
|
|
37
37
|
ConcurrencyError: () => ConcurrencyError,
|
|
38
|
+
ConsoleLogger: () => ConsoleLogger,
|
|
38
39
|
Environments: () => Environments,
|
|
39
40
|
Errors: () => Errors,
|
|
40
41
|
EventMetaSchema: () => EventMetaSchema,
|
|
@@ -56,7 +57,7 @@ __export(index_exports, {
|
|
|
56
57
|
dispose: () => dispose,
|
|
57
58
|
disposeAndExit: () => disposeAndExit,
|
|
58
59
|
extend: () => extend,
|
|
59
|
-
|
|
60
|
+
log: () => log,
|
|
60
61
|
port: () => port,
|
|
61
62
|
projection: () => projection,
|
|
62
63
|
sleep: () => sleep,
|
|
@@ -67,8 +68,107 @@ __export(index_exports, {
|
|
|
67
68
|
});
|
|
68
69
|
module.exports = __toCommonJS(index_exports);
|
|
69
70
|
|
|
70
|
-
// src/
|
|
71
|
-
var
|
|
71
|
+
// src/adapters/ConsoleLogger.ts
|
|
72
|
+
var LEVEL_VALUES = {
|
|
73
|
+
fatal: 60,
|
|
74
|
+
error: 50,
|
|
75
|
+
warn: 40,
|
|
76
|
+
info: 30,
|
|
77
|
+
debug: 20,
|
|
78
|
+
trace: 10
|
|
79
|
+
};
|
|
80
|
+
var LEVEL_COLORS = {
|
|
81
|
+
fatal: "\x1B[41m\x1B[37m",
|
|
82
|
+
// white on red bg
|
|
83
|
+
error: "\x1B[31m",
|
|
84
|
+
// red
|
|
85
|
+
warn: "\x1B[33m",
|
|
86
|
+
// yellow
|
|
87
|
+
info: "\x1B[32m",
|
|
88
|
+
// green
|
|
89
|
+
debug: "\x1B[36m",
|
|
90
|
+
// cyan
|
|
91
|
+
trace: "\x1B[90m"
|
|
92
|
+
// gray
|
|
93
|
+
};
|
|
94
|
+
var RESET = "\x1B[0m";
|
|
95
|
+
var noop = () => {
|
|
96
|
+
};
|
|
97
|
+
var ConsoleLogger = class _ConsoleLogger {
|
|
98
|
+
level;
|
|
99
|
+
_pretty;
|
|
100
|
+
fatal;
|
|
101
|
+
error;
|
|
102
|
+
warn;
|
|
103
|
+
info;
|
|
104
|
+
debug;
|
|
105
|
+
trace;
|
|
106
|
+
constructor(options = {}) {
|
|
107
|
+
const {
|
|
108
|
+
level = "info",
|
|
109
|
+
pretty = process.env.NODE_ENV !== "production",
|
|
110
|
+
bindings
|
|
111
|
+
} = options;
|
|
112
|
+
this._pretty = pretty;
|
|
113
|
+
this.level = level;
|
|
114
|
+
const threshold = LEVEL_VALUES[level] ?? 30;
|
|
115
|
+
const write = pretty ? this._prettyWrite.bind(this, bindings) : this._jsonWrite.bind(this, bindings);
|
|
116
|
+
this.fatal = write.bind(this, "fatal", 60);
|
|
117
|
+
this.error = threshold <= 50 ? write.bind(this, "error", 50) : noop;
|
|
118
|
+
this.warn = threshold <= 40 ? write.bind(this, "warn", 40) : noop;
|
|
119
|
+
this.info = threshold <= 30 ? write.bind(this, "info", 30) : noop;
|
|
120
|
+
this.debug = threshold <= 20 ? write.bind(this, "debug", 20) : noop;
|
|
121
|
+
this.trace = threshold <= 10 ? write.bind(this, "trace", 10) : noop;
|
|
122
|
+
}
|
|
123
|
+
async dispose() {
|
|
124
|
+
}
|
|
125
|
+
child(bindings) {
|
|
126
|
+
return new _ConsoleLogger({
|
|
127
|
+
level: this.level,
|
|
128
|
+
pretty: this._pretty,
|
|
129
|
+
bindings
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
_jsonWrite(bindings, level, _num, objOrMsg, msg) {
|
|
133
|
+
let obj;
|
|
134
|
+
let message;
|
|
135
|
+
if (typeof objOrMsg === "string") {
|
|
136
|
+
message = objOrMsg;
|
|
137
|
+
obj = {};
|
|
138
|
+
} else if (objOrMsg !== null && typeof objOrMsg === "object") {
|
|
139
|
+
message = msg;
|
|
140
|
+
obj = Object.fromEntries(Object.entries(objOrMsg));
|
|
141
|
+
} else {
|
|
142
|
+
message = msg;
|
|
143
|
+
obj = { value: objOrMsg };
|
|
144
|
+
}
|
|
145
|
+
const entry = Object.assign({ level, time: Date.now() }, bindings, obj);
|
|
146
|
+
if (message) entry.msg = message;
|
|
147
|
+
process.stdout.write(JSON.stringify(entry) + "\n");
|
|
148
|
+
}
|
|
149
|
+
_prettyWrite(bindings, level, _num, objOrMsg, msg) {
|
|
150
|
+
const color = LEVEL_COLORS[level];
|
|
151
|
+
const tag = `${color}${level.toUpperCase().padEnd(5)}${RESET}`;
|
|
152
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
153
|
+
let message;
|
|
154
|
+
let data;
|
|
155
|
+
if (typeof objOrMsg === "string") {
|
|
156
|
+
message = objOrMsg;
|
|
157
|
+
} else {
|
|
158
|
+
message = msg ?? "";
|
|
159
|
+
if (objOrMsg !== void 0 && objOrMsg !== null) {
|
|
160
|
+
try {
|
|
161
|
+
data = JSON.stringify(objOrMsg);
|
|
162
|
+
} catch {
|
|
163
|
+
data = "[unserializable]";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const bindStr = bindings && Object.keys(bindings).length ? ` ${JSON.stringify(bindings)}` : "";
|
|
168
|
+
const parts = [ts, tag, message, data, bindStr].filter(Boolean);
|
|
169
|
+
process.stdout.write(parts.join(" ") + "\n");
|
|
170
|
+
}
|
|
171
|
+
};
|
|
72
172
|
|
|
73
173
|
// src/adapters/InMemoryCache.ts
|
|
74
174
|
var InMemoryCache = class {
|
|
@@ -536,28 +636,30 @@ var InMemoryStore = class {
|
|
|
536
636
|
|
|
537
637
|
// src/ports.ts
|
|
538
638
|
var ExitCodes = ["ERROR", "EXIT"];
|
|
539
|
-
var logger = (0, import_pino.pino)({
|
|
540
|
-
transport: config().env !== "production" ? {
|
|
541
|
-
target: "pino-pretty",
|
|
542
|
-
options: {
|
|
543
|
-
ignore: "pid,hostname",
|
|
544
|
-
singleLine: config().logSingleLine,
|
|
545
|
-
colorize: true
|
|
546
|
-
}
|
|
547
|
-
} : void 0,
|
|
548
|
-
level: config().logLevel
|
|
549
|
-
});
|
|
550
639
|
var adapters = /* @__PURE__ */ new Map();
|
|
551
640
|
function port(injector) {
|
|
552
641
|
return function(adapter) {
|
|
553
642
|
if (!adapters.has(injector.name)) {
|
|
554
643
|
const injected = injector(adapter);
|
|
555
644
|
adapters.set(injector.name, injected);
|
|
556
|
-
|
|
645
|
+
console.log(`[act] + ${injector.name}:${injected.constructor.name}`);
|
|
557
646
|
}
|
|
558
647
|
return adapters.get(injector.name);
|
|
559
648
|
};
|
|
560
649
|
}
|
|
650
|
+
var log = port(function log2(adapter) {
|
|
651
|
+
const cfg = config();
|
|
652
|
+
return adapter || new ConsoleLogger({
|
|
653
|
+
level: cfg.logLevel,
|
|
654
|
+
pretty: cfg.env !== "production"
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
var store = port(function store2(adapter) {
|
|
658
|
+
return adapter || new InMemoryStore();
|
|
659
|
+
});
|
|
660
|
+
var cache = port(function cache2(adapter) {
|
|
661
|
+
return adapter || new InMemoryCache();
|
|
662
|
+
});
|
|
561
663
|
var disposers = [];
|
|
562
664
|
async function disposeAndExit(code = "EXIT") {
|
|
563
665
|
if (code === "ERROR" && config().env === "production") return;
|
|
@@ -565,7 +667,7 @@ async function disposeAndExit(code = "EXIT") {
|
|
|
565
667
|
await Promise.all(
|
|
566
668
|
[...adapters.values()].reverse().map(async (adapter) => {
|
|
567
669
|
await adapter.dispose();
|
|
568
|
-
|
|
670
|
+
console.log(`[act] - ${adapter.constructor.name}`);
|
|
569
671
|
})
|
|
570
672
|
);
|
|
571
673
|
adapters.clear();
|
|
@@ -576,14 +678,9 @@ function dispose(disposer) {
|
|
|
576
678
|
return disposeAndExit;
|
|
577
679
|
}
|
|
578
680
|
var SNAP_EVENT = "__snapshot__";
|
|
579
|
-
var store = port(function store2(adapter) {
|
|
580
|
-
return adapter || new InMemoryStore();
|
|
581
|
-
});
|
|
582
|
-
var cache = port(function cache2(adapter) {
|
|
583
|
-
return adapter || new InMemoryCache();
|
|
584
|
-
});
|
|
585
681
|
function build_tracer(logLevel2) {
|
|
586
682
|
if (logLevel2 === "trace") {
|
|
683
|
+
const logger4 = log();
|
|
587
684
|
return {
|
|
588
685
|
fetched: (fetched) => {
|
|
589
686
|
const data = Object.fromEntries(
|
|
@@ -595,23 +692,23 @@ function build_tracer(logLevel2) {
|
|
|
595
692
|
return [key, value];
|
|
596
693
|
})
|
|
597
694
|
);
|
|
598
|
-
|
|
695
|
+
logger4.trace(data, ">> fetch");
|
|
599
696
|
},
|
|
600
697
|
correlated: (streams) => {
|
|
601
698
|
const data = streams.map(({ stream }) => stream).join(" ");
|
|
602
|
-
|
|
699
|
+
logger4.trace(`>> correlate ${data}`);
|
|
603
700
|
},
|
|
604
701
|
leased: (leases) => {
|
|
605
702
|
const data = Object.fromEntries(
|
|
606
703
|
leases.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
607
704
|
);
|
|
608
|
-
|
|
705
|
+
logger4.trace(data, ">> lease");
|
|
609
706
|
},
|
|
610
707
|
acked: (leases) => {
|
|
611
708
|
const data = Object.fromEntries(
|
|
612
709
|
leases.map(({ stream, at, retry }) => [stream, { at, retry }])
|
|
613
710
|
);
|
|
614
|
-
|
|
711
|
+
logger4.trace(data, ">> ack");
|
|
615
712
|
},
|
|
616
713
|
blocked: (leases) => {
|
|
617
714
|
const data = Object.fromEntries(
|
|
@@ -620,7 +717,7 @@ function build_tracer(logLevel2) {
|
|
|
620
717
|
{ at, retry, error }
|
|
621
718
|
])
|
|
622
719
|
);
|
|
623
|
-
|
|
720
|
+
logger4.trace(data, ">> block");
|
|
624
721
|
}
|
|
625
722
|
};
|
|
626
723
|
} else {
|
|
@@ -640,6 +737,7 @@ function build_tracer(logLevel2) {
|
|
|
640
737
|
}
|
|
641
738
|
|
|
642
739
|
// src/signals.ts
|
|
740
|
+
var logger = log();
|
|
643
741
|
process.once("SIGINT", async (arg) => {
|
|
644
742
|
logger.info(arg, "SIGINT");
|
|
645
743
|
await disposeAndExit("EXIT");
|
|
@@ -664,6 +762,7 @@ var import_events = __toESM(require("events"), 1);
|
|
|
664
762
|
// src/event-sourcing.ts
|
|
665
763
|
var import_act_patch = require("@rotorsoft/act-patch");
|
|
666
764
|
var import_crypto = require("crypto");
|
|
765
|
+
var logger2 = log();
|
|
667
766
|
async function snap(snapshot) {
|
|
668
767
|
try {
|
|
669
768
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
@@ -677,9 +776,9 @@ async function snap(snapshot) {
|
|
|
677
776
|
version
|
|
678
777
|
// IMPORTANT! - state events are committed right after the snapshot event
|
|
679
778
|
);
|
|
680
|
-
|
|
779
|
+
logger2.trace(snapped, "\u{1F7E0} snap");
|
|
681
780
|
} catch (error) {
|
|
682
|
-
|
|
781
|
+
logger2.error(error);
|
|
683
782
|
}
|
|
684
783
|
}
|
|
685
784
|
async function load(me, stream, callback) {
|
|
@@ -703,7 +802,7 @@ async function load(me, stream, callback) {
|
|
|
703
802
|
},
|
|
704
803
|
{ stream, with_snaps: !cached, after: cached?.event_id }
|
|
705
804
|
);
|
|
706
|
-
|
|
805
|
+
logger2.trace(
|
|
707
806
|
state2,
|
|
708
807
|
`\u{1F7E2} load ${stream}${cached && count === 0 ? " (cached)" : ""}`
|
|
709
808
|
);
|
|
@@ -715,7 +814,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
715
814
|
payload = skipValidation ? payload : validate(action2, payload, me.actions[action2]);
|
|
716
815
|
const snapshot = await load(me, stream);
|
|
717
816
|
const expected = expectedVersion || snapshot.event?.version;
|
|
718
|
-
|
|
817
|
+
logger2.trace(
|
|
719
818
|
payload,
|
|
720
819
|
`\u{1F535} ${stream}.${action2}${typeof expected === "number" ? `.${expected}` : ""}`
|
|
721
820
|
);
|
|
@@ -758,7 +857,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
758
857
|
} : void 0
|
|
759
858
|
}
|
|
760
859
|
};
|
|
761
|
-
|
|
860
|
+
logger2.trace(
|
|
762
861
|
emitted.map((e) => e.data),
|
|
763
862
|
`\u{1F534} commit ${stream}.${emitted.map((e) => e.name).join(", ")}`
|
|
764
863
|
);
|
|
@@ -798,6 +897,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
798
897
|
}
|
|
799
898
|
|
|
800
899
|
// src/act.ts
|
|
900
|
+
var logger3 = log();
|
|
801
901
|
var tracer = build_tracer(config().logLevel);
|
|
802
902
|
var Act = class {
|
|
803
903
|
constructor(registry, _states = /* @__PURE__ */ new Map()) {
|
|
@@ -1078,7 +1178,7 @@ var Act = class {
|
|
|
1078
1178
|
if (payloads.length === 0) return { lease, handled: 0, at: lease.at };
|
|
1079
1179
|
const stream = lease.stream;
|
|
1080
1180
|
let at = payloads.at(0).event.id, handled = 0;
|
|
1081
|
-
lease.retry > 0 &&
|
|
1181
|
+
lease.retry > 0 && logger3.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
|
|
1082
1182
|
for (const payload of payloads) {
|
|
1083
1183
|
const { event, handler, options } = payload;
|
|
1084
1184
|
try {
|
|
@@ -1086,9 +1186,9 @@ var Act = class {
|
|
|
1086
1186
|
at = event.id;
|
|
1087
1187
|
handled++;
|
|
1088
1188
|
} catch (error) {
|
|
1089
|
-
|
|
1189
|
+
logger3.error(error);
|
|
1090
1190
|
const block = lease.retry >= options.maxRetries && options.blockOnError;
|
|
1091
|
-
block &&
|
|
1191
|
+
block && logger3.error(`Blocking ${stream} after ${lease.retry} retries.`);
|
|
1092
1192
|
return {
|
|
1093
1193
|
lease,
|
|
1094
1194
|
handled,
|
|
@@ -1232,7 +1332,7 @@ var Act = class {
|
|
|
1232
1332
|
this._needs_drain = false;
|
|
1233
1333
|
return result;
|
|
1234
1334
|
} catch (error) {
|
|
1235
|
-
|
|
1335
|
+
logger3.error(error);
|
|
1236
1336
|
} finally {
|
|
1237
1337
|
this._drain_locked = false;
|
|
1238
1338
|
}
|
|
@@ -1505,7 +1605,7 @@ var Act = class {
|
|
|
1505
1605
|
if (!lastDrain.acked.length && !lastDrain.blocked.length) break;
|
|
1506
1606
|
}
|
|
1507
1607
|
if (lastDrain) this.emit("settled", lastDrain);
|
|
1508
|
-
})().catch((err) =>
|
|
1608
|
+
})().catch((err) => logger3.error(err)).finally(() => {
|
|
1509
1609
|
this._settling = false;
|
|
1510
1610
|
});
|
|
1511
1611
|
}, debounceMs);
|
|
@@ -1552,15 +1652,35 @@ function registerState(state2, states, actions, events) {
|
|
|
1552
1652
|
}
|
|
1553
1653
|
for (const name of Object.keys(state2.events)) {
|
|
1554
1654
|
if (existing.events[name] === state2.events[name]) continue;
|
|
1655
|
+
if (existing.events[name]) continue;
|
|
1555
1656
|
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
1556
1657
|
}
|
|
1658
|
+
const mergedPatch = { ...existing.patch };
|
|
1659
|
+
for (const name of Object.keys(state2.patch)) {
|
|
1660
|
+
const existingP = existing.patch[name];
|
|
1661
|
+
const incomingP = state2.patch[name];
|
|
1662
|
+
if (!existingP) {
|
|
1663
|
+
mergedPatch[name] = incomingP;
|
|
1664
|
+
} else {
|
|
1665
|
+
const existingIsDefault = existingP._passthrough;
|
|
1666
|
+
const incomingIsDefault = incomingP._passthrough;
|
|
1667
|
+
if (!existingIsDefault && !incomingIsDefault && existingP !== incomingP) {
|
|
1668
|
+
throw new Error(
|
|
1669
|
+
`Duplicate custom patch for event "${name}" in state "${state2.name}"`
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1672
|
+
if (existingIsDefault && !incomingIsDefault) {
|
|
1673
|
+
mergedPatch[name] = incomingP;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1557
1677
|
const merged = {
|
|
1558
1678
|
...existing,
|
|
1559
1679
|
state: mergeSchemas(existing.state, state2.state, state2.name),
|
|
1560
1680
|
init: mergeInits(existing.init, state2.init),
|
|
1561
1681
|
events: { ...existing.events, ...state2.events },
|
|
1562
1682
|
actions: { ...existing.actions, ...state2.actions },
|
|
1563
|
-
patch:
|
|
1683
|
+
patch: mergedPatch,
|
|
1564
1684
|
on: { ...existing.on, ...state2.on },
|
|
1565
1685
|
given: { ...existing.given, ...state2.given },
|
|
1566
1686
|
snap: state2.snap || existing.snap
|
|
@@ -1841,10 +1961,11 @@ function state(entry) {
|
|
|
1841
1961
|
return {
|
|
1842
1962
|
emits(events) {
|
|
1843
1963
|
const defaultPatch = Object.fromEntries(
|
|
1844
|
-
Object.keys(events).map((k) =>
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1964
|
+
Object.keys(events).map((k) => {
|
|
1965
|
+
const fn = ({ data }) => data;
|
|
1966
|
+
fn._passthrough = true;
|
|
1967
|
+
return [k, fn];
|
|
1968
|
+
})
|
|
1848
1969
|
);
|
|
1849
1970
|
const builder = action_builder({
|
|
1850
1971
|
events,
|
|
@@ -1926,6 +2047,7 @@ function action_builder(state2) {
|
|
|
1926
2047
|
CausationEventSchema,
|
|
1927
2048
|
CommittedMetaSchema,
|
|
1928
2049
|
ConcurrencyError,
|
|
2050
|
+
ConsoleLogger,
|
|
1929
2051
|
Environments,
|
|
1930
2052
|
Errors,
|
|
1931
2053
|
EventMetaSchema,
|
|
@@ -1947,7 +2069,7 @@ function action_builder(state2) {
|
|
|
1947
2069
|
dispose,
|
|
1948
2070
|
disposeAndExit,
|
|
1949
2071
|
extend,
|
|
1950
|
-
|
|
2072
|
+
log,
|
|
1951
2073
|
port,
|
|
1952
2074
|
projection,
|
|
1953
2075
|
sleep,
|