@rotorsoft/act 0.21.0 → 0.22.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/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 +90 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +90 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -225,16 +225,18 @@ export interface Store extends Disposable {
|
|
|
225
225
|
* Upserts stream entries so they become visible to {@link claim}. Used by
|
|
226
226
|
* `correlate()` to register dynamically discovered reaction target streams.
|
|
227
227
|
*
|
|
228
|
+
* Also returns the current maximum watermark across all subscribed streams,
|
|
229
|
+
* used internally for correlation checkpoint initialization on cold start.
|
|
230
|
+
*
|
|
228
231
|
* @param streams - Streams to register with optional source hint
|
|
229
|
-
* @returns
|
|
232
|
+
* @returns `subscribed` count of newly registered streams, `watermark` max `at` across all streams
|
|
230
233
|
*
|
|
231
234
|
* @example
|
|
232
235
|
* ```typescript
|
|
233
|
-
* const
|
|
236
|
+
* const { subscribed, watermark } = await store().subscribe([
|
|
234
237
|
* { stream: "stats-user-1", source: "user-1" },
|
|
235
238
|
* { stream: "stats-user-2", source: "user-2" },
|
|
236
239
|
* ]);
|
|
237
|
-
* console.log(`Registered ${count} new streams`);
|
|
238
240
|
* ```
|
|
239
241
|
*
|
|
240
242
|
* @see {@link claim} for discovering and leasing registered streams
|
|
@@ -242,7 +244,10 @@ export interface Store extends Disposable {
|
|
|
242
244
|
subscribe: (streams: Array<{
|
|
243
245
|
stream: string;
|
|
244
246
|
source?: string;
|
|
245
|
-
}>) => Promise<
|
|
247
|
+
}>) => Promise<{
|
|
248
|
+
subscribed: number;
|
|
249
|
+
watermark: number;
|
|
250
|
+
}>;
|
|
246
251
|
/**
|
|
247
252
|
* Blocks streams after persistent processing failures.
|
|
248
253
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../src/types/ports.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EACT,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACR,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;GAIG;AACH,MAAM,WAAW,UAAU,CAAC,MAAM,SAAS,MAAM;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,KAAM,SAAQ,UAAU;IACvC,GAAG,CAAC,MAAM,SAAS,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IAC3C,GAAG,CAAC,MAAM,SAAS,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,WAAW,KAAM,SAAQ,UAAU;IACvC;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,MAAM,EAAE,CAAC,CAAC,SAAS,OAAO,EACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,EAC3B,IAAI,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,KACrB,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,KAAK,EAAE,CAAC,CAAC,SAAS,OAAO,EACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,EAChD,KAAK,CAAC,EAAE,KAAK,KACV,OAAO,CAAC,MAAM,CAAC,CAAC;IAErB;;;;;;;;;;;;;;;;;OAiBG;IACH,GAAG,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,KAAK,EAAE,CACL,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAEtB
|
|
1
|
+
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../src/types/ports.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -496,18 +496,22 @@ var InMemoryStore = class {
|
|
|
496
496
|
/**
|
|
497
497
|
* Registers streams for event processing.
|
|
498
498
|
* @param streams - Streams to register with optional source.
|
|
499
|
-
* @returns
|
|
499
|
+
* @returns subscribed count and current max watermark.
|
|
500
500
|
*/
|
|
501
501
|
async subscribe(streams) {
|
|
502
502
|
await sleep();
|
|
503
|
-
let
|
|
503
|
+
let subscribed = 0;
|
|
504
504
|
for (const { stream, source } of streams) {
|
|
505
505
|
if (!this._streams.has(stream)) {
|
|
506
506
|
this._streams.set(stream, new InMemoryStream(stream, source));
|
|
507
|
-
|
|
507
|
+
subscribed++;
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
|
-
|
|
510
|
+
let watermark = -1;
|
|
511
|
+
for (const s of this._streams.values()) {
|
|
512
|
+
if (s.at > watermark) watermark = s.at;
|
|
513
|
+
}
|
|
514
|
+
return { subscribed, watermark };
|
|
511
515
|
}
|
|
512
516
|
/**
|
|
513
517
|
* Acknowledge completion of processing for leased streams.
|
|
@@ -794,15 +798,21 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
794
798
|
// src/act.ts
|
|
795
799
|
var tracer = build_tracer(config().logLevel);
|
|
796
800
|
var Act = class {
|
|
797
|
-
/**
|
|
798
|
-
* Create a new Act orchestrator.
|
|
799
|
-
*
|
|
800
|
-
* @param registry The registry of state, event, and action schemas
|
|
801
|
-
* @param states Map of state names to their (potentially merged) state definitions
|
|
802
|
-
*/
|
|
803
801
|
constructor(registry, _states = /* @__PURE__ */ new Map()) {
|
|
804
802
|
this.registry = registry;
|
|
805
803
|
this._states = _states;
|
|
804
|
+
const statics = [];
|
|
805
|
+
for (const register of Object.values(this.registry.events)) {
|
|
806
|
+
for (const reaction of register.reactions.values()) {
|
|
807
|
+
if (typeof reaction.resolver === "function") {
|
|
808
|
+
this._has_dynamic_resolvers = true;
|
|
809
|
+
} else if (reaction.resolver) {
|
|
810
|
+
const r = reaction.resolver;
|
|
811
|
+
statics.push({ stream: r.target, source: r.source });
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
this._static_targets = statics;
|
|
806
816
|
dispose(() => {
|
|
807
817
|
this._emitter.removeAllListeners();
|
|
808
818
|
this.stop_correlations();
|
|
@@ -816,6 +826,10 @@ var Act = class {
|
|
|
816
826
|
_correlation_timer = void 0;
|
|
817
827
|
_settle_timer = void 0;
|
|
818
828
|
_settling = false;
|
|
829
|
+
_correlation_checkpoint = -1;
|
|
830
|
+
_subscribed_statics = /* @__PURE__ */ new Set();
|
|
831
|
+
_has_dynamic_resolvers = false;
|
|
832
|
+
_correlation_initialized = false;
|
|
819
833
|
emit(event, args) {
|
|
820
834
|
return this._emitter.emit(event, args);
|
|
821
835
|
}
|
|
@@ -827,6 +841,14 @@ var Act = class {
|
|
|
827
841
|
this._emitter.off(event, listener);
|
|
828
842
|
return this;
|
|
829
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* Create a new Act orchestrator.
|
|
846
|
+
*
|
|
847
|
+
* @param registry The registry of state, event, and action schemas
|
|
848
|
+
* @param states Map of state names to their (potentially merged) state definitions
|
|
849
|
+
*/
|
|
850
|
+
/** Static resolver targets collected at build time */
|
|
851
|
+
_static_targets;
|
|
830
852
|
/**
|
|
831
853
|
* Executes an action on a state instance, committing resulting events.
|
|
832
854
|
*
|
|
@@ -1236,37 +1258,67 @@ var Act = class {
|
|
|
1236
1258
|
* @see {@link start_correlations} for automatic periodic correlation
|
|
1237
1259
|
* @see {@link stop_correlations} to stop automatic correlation
|
|
1238
1260
|
*/
|
|
1261
|
+
/**
|
|
1262
|
+
* Initialize correlation state on first call.
|
|
1263
|
+
* - Reads max(at) from store as cold-start checkpoint
|
|
1264
|
+
* - Subscribes static resolver targets (idempotent upsert)
|
|
1265
|
+
* - Populates the subscribed statics set
|
|
1266
|
+
* @internal
|
|
1267
|
+
*/
|
|
1268
|
+
async _init_correlation() {
|
|
1269
|
+
if (this._correlation_initialized) return;
|
|
1270
|
+
this._correlation_initialized = true;
|
|
1271
|
+
const { watermark } = await store().subscribe(this._static_targets);
|
|
1272
|
+
this._correlation_checkpoint = watermark;
|
|
1273
|
+
for (const { stream } of this._static_targets) {
|
|
1274
|
+
this._subscribed_statics.add(stream);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1239
1277
|
async correlate(query = { after: -1, limit: 10 }) {
|
|
1278
|
+
await this._init_correlation();
|
|
1279
|
+
if (!this._has_dynamic_resolvers)
|
|
1280
|
+
return { subscribed: 0, last_id: this._correlation_checkpoint };
|
|
1281
|
+
const after = Math.max(this._correlation_checkpoint, query.after || -1);
|
|
1240
1282
|
const correlated = /* @__PURE__ */ new Map();
|
|
1241
|
-
let last_id =
|
|
1242
|
-
await store().query(
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
const
|
|
1248
|
-
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1283
|
+
let last_id = after;
|
|
1284
|
+
await store().query(
|
|
1285
|
+
(event) => {
|
|
1286
|
+
last_id = event.id;
|
|
1287
|
+
const register = this.registry.events[event.name];
|
|
1288
|
+
if (register) {
|
|
1289
|
+
for (const reaction of register.reactions.values()) {
|
|
1290
|
+
if (typeof reaction.resolver !== "function") continue;
|
|
1291
|
+
const resolved = reaction.resolver(event);
|
|
1292
|
+
if (resolved && !this._subscribed_statics.has(resolved.target)) {
|
|
1293
|
+
const entry = correlated.get(resolved.target) || {
|
|
1294
|
+
source: resolved.source,
|
|
1295
|
+
payloads: []
|
|
1296
|
+
};
|
|
1297
|
+
entry.payloads.push({
|
|
1298
|
+
...reaction,
|
|
1299
|
+
source: resolved.source,
|
|
1300
|
+
event
|
|
1301
|
+
});
|
|
1302
|
+
correlated.set(resolved.target, entry);
|
|
1303
|
+
}
|
|
1259
1304
|
}
|
|
1260
1305
|
}
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1306
|
+
},
|
|
1307
|
+
{ ...query, after }
|
|
1308
|
+
);
|
|
1309
|
+
this._correlation_checkpoint = last_id;
|
|
1263
1310
|
if (correlated.size) {
|
|
1264
1311
|
const streams = [...correlated.entries()].map(([stream, { source }]) => ({
|
|
1265
1312
|
stream,
|
|
1266
1313
|
source
|
|
1267
1314
|
}));
|
|
1268
|
-
const subscribed = await store().subscribe(streams);
|
|
1269
|
-
|
|
1315
|
+
const { subscribed } = await store().subscribe(streams);
|
|
1316
|
+
if (subscribed) {
|
|
1317
|
+
tracer.correlated(streams);
|
|
1318
|
+
for (const { stream } of streams) {
|
|
1319
|
+
this._subscribed_statics.add(stream);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1270
1322
|
return { subscribed, last_id };
|
|
1271
1323
|
}
|
|
1272
1324
|
return { subscribed: 0, last_id };
|
|
@@ -1329,10 +1381,8 @@ var Act = class {
|
|
|
1329
1381
|
start_correlations(query = {}, frequency = 1e4, callback) {
|
|
1330
1382
|
if (this._correlation_timer) return false;
|
|
1331
1383
|
const limit = query.limit || 100;
|
|
1332
|
-
let after = query.after || -1;
|
|
1333
1384
|
this._correlation_timer = setInterval(
|
|
1334
|
-
() => this.correlate({ ...query, after, limit }).then((result) => {
|
|
1335
|
-
after = result.last_id;
|
|
1385
|
+
() => this.correlate({ ...query, after: this._correlation_checkpoint, limit }).then((result) => {
|
|
1336
1386
|
if (callback && result.subscribed) callback(result.subscribed);
|
|
1337
1387
|
}).catch(console.error),
|
|
1338
1388
|
frequency
|
|
@@ -1415,9 +1465,13 @@ var Act = class {
|
|
|
1415
1465
|
if (this._settling) return;
|
|
1416
1466
|
this._settling = true;
|
|
1417
1467
|
(async () => {
|
|
1468
|
+
await this._init_correlation();
|
|
1418
1469
|
let lastDrain;
|
|
1419
1470
|
for (let i = 0; i < maxPasses; i++) {
|
|
1420
|
-
const { subscribed } = await this.correlate(
|
|
1471
|
+
const { subscribed } = await this.correlate({
|
|
1472
|
+
...correlateQuery,
|
|
1473
|
+
after: this._correlation_checkpoint
|
|
1474
|
+
});
|
|
1421
1475
|
if (subscribed === 0 && i > 0) break;
|
|
1422
1476
|
lastDrain = await this.drain(drainOptions);
|
|
1423
1477
|
if (!lastDrain.acked.length && !lastDrain.blocked.length) break;
|