@rotorsoft/act 0.21.0 → 0.23.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 +1 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +14 -0
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/InMemoryStore.d.ts +5 -2
- package/dist/@types/adapters/InMemoryStore.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +9 -4
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/index.cjs +95 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +95 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -401,7 +401,11 @@ var InMemoryStore = class {
|
|
|
401
401
|
*/
|
|
402
402
|
async claim(lagging, leading, by, millis) {
|
|
403
403
|
await sleep();
|
|
404
|
-
const available = [...this._streams.values()].filter(
|
|
404
|
+
const available = [...this._streams.values()].filter(
|
|
405
|
+
(s) => s.is_avaliable && (s.at < 0 || this._events.some(
|
|
406
|
+
(e) => e.id > s.at && e.name !== SNAP_EVENT && (!s.source || RegExp(s.source).test(e.stream))
|
|
407
|
+
))
|
|
408
|
+
);
|
|
405
409
|
const lag = available.sort((a, b) => a.at - b.at).slice(0, lagging).map((s) => ({
|
|
406
410
|
stream: s.stream,
|
|
407
411
|
source: s.source,
|
|
@@ -427,18 +431,22 @@ var InMemoryStore = class {
|
|
|
427
431
|
/**
|
|
428
432
|
* Registers streams for event processing.
|
|
429
433
|
* @param streams - Streams to register with optional source.
|
|
430
|
-
* @returns
|
|
434
|
+
* @returns subscribed count and current max watermark.
|
|
431
435
|
*/
|
|
432
436
|
async subscribe(streams) {
|
|
433
437
|
await sleep();
|
|
434
|
-
let
|
|
438
|
+
let subscribed = 0;
|
|
435
439
|
for (const { stream, source } of streams) {
|
|
436
440
|
if (!this._streams.has(stream)) {
|
|
437
441
|
this._streams.set(stream, new InMemoryStream(stream, source));
|
|
438
|
-
|
|
442
|
+
subscribed++;
|
|
439
443
|
}
|
|
440
444
|
}
|
|
441
|
-
|
|
445
|
+
let watermark = -1;
|
|
446
|
+
for (const s of this._streams.values()) {
|
|
447
|
+
if (s.at > watermark) watermark = s.at;
|
|
448
|
+
}
|
|
449
|
+
return { subscribed, watermark };
|
|
442
450
|
}
|
|
443
451
|
/**
|
|
444
452
|
* Acknowledge completion of processing for leased streams.
|
|
@@ -725,15 +733,21 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
725
733
|
// src/act.ts
|
|
726
734
|
var tracer = build_tracer(config().logLevel);
|
|
727
735
|
var Act = class {
|
|
728
|
-
/**
|
|
729
|
-
* Create a new Act orchestrator.
|
|
730
|
-
*
|
|
731
|
-
* @param registry The registry of state, event, and action schemas
|
|
732
|
-
* @param states Map of state names to their (potentially merged) state definitions
|
|
733
|
-
*/
|
|
734
736
|
constructor(registry, _states = /* @__PURE__ */ new Map()) {
|
|
735
737
|
this.registry = registry;
|
|
736
738
|
this._states = _states;
|
|
739
|
+
const statics = [];
|
|
740
|
+
for (const register of Object.values(this.registry.events)) {
|
|
741
|
+
for (const reaction of register.reactions.values()) {
|
|
742
|
+
if (typeof reaction.resolver === "function") {
|
|
743
|
+
this._has_dynamic_resolvers = true;
|
|
744
|
+
} else if (reaction.resolver) {
|
|
745
|
+
const r = reaction.resolver;
|
|
746
|
+
statics.push({ stream: r.target, source: r.source });
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
this._static_targets = statics;
|
|
737
751
|
dispose(() => {
|
|
738
752
|
this._emitter.removeAllListeners();
|
|
739
753
|
this.stop_correlations();
|
|
@@ -747,6 +761,10 @@ var Act = class {
|
|
|
747
761
|
_correlation_timer = void 0;
|
|
748
762
|
_settle_timer = void 0;
|
|
749
763
|
_settling = false;
|
|
764
|
+
_correlation_checkpoint = -1;
|
|
765
|
+
_subscribed_statics = /* @__PURE__ */ new Set();
|
|
766
|
+
_has_dynamic_resolvers = false;
|
|
767
|
+
_correlation_initialized = false;
|
|
750
768
|
emit(event, args) {
|
|
751
769
|
return this._emitter.emit(event, args);
|
|
752
770
|
}
|
|
@@ -758,6 +776,14 @@ var Act = class {
|
|
|
758
776
|
this._emitter.off(event, listener);
|
|
759
777
|
return this;
|
|
760
778
|
}
|
|
779
|
+
/**
|
|
780
|
+
* Create a new Act orchestrator.
|
|
781
|
+
*
|
|
782
|
+
* @param registry The registry of state, event, and action schemas
|
|
783
|
+
* @param states Map of state names to their (potentially merged) state definitions
|
|
784
|
+
*/
|
|
785
|
+
/** Static resolver targets collected at build time */
|
|
786
|
+
_static_targets;
|
|
761
787
|
/**
|
|
762
788
|
* Executes an action on a state instance, committing resulting events.
|
|
763
789
|
*
|
|
@@ -1167,37 +1193,67 @@ var Act = class {
|
|
|
1167
1193
|
* @see {@link start_correlations} for automatic periodic correlation
|
|
1168
1194
|
* @see {@link stop_correlations} to stop automatic correlation
|
|
1169
1195
|
*/
|
|
1196
|
+
/**
|
|
1197
|
+
* Initialize correlation state on first call.
|
|
1198
|
+
* - Reads max(at) from store as cold-start checkpoint
|
|
1199
|
+
* - Subscribes static resolver targets (idempotent upsert)
|
|
1200
|
+
* - Populates the subscribed statics set
|
|
1201
|
+
* @internal
|
|
1202
|
+
*/
|
|
1203
|
+
async _init_correlation() {
|
|
1204
|
+
if (this._correlation_initialized) return;
|
|
1205
|
+
this._correlation_initialized = true;
|
|
1206
|
+
const { watermark } = await store().subscribe(this._static_targets);
|
|
1207
|
+
this._correlation_checkpoint = watermark;
|
|
1208
|
+
for (const { stream } of this._static_targets) {
|
|
1209
|
+
this._subscribed_statics.add(stream);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1170
1212
|
async correlate(query = { after: -1, limit: 10 }) {
|
|
1213
|
+
await this._init_correlation();
|
|
1214
|
+
if (!this._has_dynamic_resolvers)
|
|
1215
|
+
return { subscribed: 0, last_id: this._correlation_checkpoint };
|
|
1216
|
+
const after = Math.max(this._correlation_checkpoint, query.after || -1);
|
|
1171
1217
|
const correlated = /* @__PURE__ */ new Map();
|
|
1172
|
-
let last_id =
|
|
1173
|
-
await store().query(
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1218
|
+
let last_id = after;
|
|
1219
|
+
await store().query(
|
|
1220
|
+
(event) => {
|
|
1221
|
+
last_id = event.id;
|
|
1222
|
+
const register = this.registry.events[event.name];
|
|
1223
|
+
if (register) {
|
|
1224
|
+
for (const reaction of register.reactions.values()) {
|
|
1225
|
+
if (typeof reaction.resolver !== "function") continue;
|
|
1226
|
+
const resolved = reaction.resolver(event);
|
|
1227
|
+
if (resolved && !this._subscribed_statics.has(resolved.target)) {
|
|
1228
|
+
const entry = correlated.get(resolved.target) || {
|
|
1229
|
+
source: resolved.source,
|
|
1230
|
+
payloads: []
|
|
1231
|
+
};
|
|
1232
|
+
entry.payloads.push({
|
|
1233
|
+
...reaction,
|
|
1234
|
+
source: resolved.source,
|
|
1235
|
+
event
|
|
1236
|
+
});
|
|
1237
|
+
correlated.set(resolved.target, entry);
|
|
1238
|
+
}
|
|
1190
1239
|
}
|
|
1191
1240
|
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1241
|
+
},
|
|
1242
|
+
{ ...query, after }
|
|
1243
|
+
);
|
|
1244
|
+
this._correlation_checkpoint = last_id;
|
|
1194
1245
|
if (correlated.size) {
|
|
1195
1246
|
const streams = [...correlated.entries()].map(([stream, { source }]) => ({
|
|
1196
1247
|
stream,
|
|
1197
1248
|
source
|
|
1198
1249
|
}));
|
|
1199
|
-
const subscribed = await store().subscribe(streams);
|
|
1200
|
-
|
|
1250
|
+
const { subscribed } = await store().subscribe(streams);
|
|
1251
|
+
if (subscribed) {
|
|
1252
|
+
tracer.correlated(streams);
|
|
1253
|
+
for (const { stream } of streams) {
|
|
1254
|
+
this._subscribed_statics.add(stream);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1201
1257
|
return { subscribed, last_id };
|
|
1202
1258
|
}
|
|
1203
1259
|
return { subscribed: 0, last_id };
|
|
@@ -1260,10 +1316,8 @@ var Act = class {
|
|
|
1260
1316
|
start_correlations(query = {}, frequency = 1e4, callback) {
|
|
1261
1317
|
if (this._correlation_timer) return false;
|
|
1262
1318
|
const limit = query.limit || 100;
|
|
1263
|
-
let after = query.after || -1;
|
|
1264
1319
|
this._correlation_timer = setInterval(
|
|
1265
|
-
() => this.correlate({ ...query, after, limit }).then((result) => {
|
|
1266
|
-
after = result.last_id;
|
|
1320
|
+
() => this.correlate({ ...query, after: this._correlation_checkpoint, limit }).then((result) => {
|
|
1267
1321
|
if (callback && result.subscribed) callback(result.subscribed);
|
|
1268
1322
|
}).catch(console.error),
|
|
1269
1323
|
frequency
|
|
@@ -1346,9 +1400,13 @@ var Act = class {
|
|
|
1346
1400
|
if (this._settling) return;
|
|
1347
1401
|
this._settling = true;
|
|
1348
1402
|
(async () => {
|
|
1403
|
+
await this._init_correlation();
|
|
1349
1404
|
let lastDrain;
|
|
1350
1405
|
for (let i = 0; i < maxPasses; i++) {
|
|
1351
|
-
const { subscribed } = await this.correlate(
|
|
1406
|
+
const { subscribed } = await this.correlate({
|
|
1407
|
+
...correlateQuery,
|
|
1408
|
+
after: this._correlation_checkpoint
|
|
1409
|
+
});
|
|
1352
1410
|
if (subscribed === 0 && i > 0) break;
|
|
1353
1411
|
lastDrain = await this.drain(drainOptions);
|
|
1354
1412
|
if (!lastDrain.acked.length && !lastDrain.blocked.length) break;
|