@rotorsoft/act 1.23.32 → 1.23.34
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 -0
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
- package/dist/@types/internal/close-cycle.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts +18 -0
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/{chunk-5B45U2IS.js → chunk-TTOT5CRM.js} +5 -2
- package/dist/{chunk-5B45U2IS.js.map → chunk-TTOT5CRM.js.map} +1 -1
- package/dist/index.cjs +59 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +56 -4
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +4 -1
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
sleep,
|
|
22
22
|
store,
|
|
23
23
|
validate
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TTOT5CRM.js";
|
|
25
25
|
import {
|
|
26
26
|
ActorSchema,
|
|
27
27
|
CausationEventSchema,
|
|
@@ -1430,14 +1430,19 @@ async function scan_stream_heads(streams) {
|
|
|
1430
1430
|
const stats = await store().query_stats(streams, {
|
|
1431
1431
|
exclude: [SNAP_EVENT]
|
|
1432
1432
|
});
|
|
1433
|
+
const domain_heads = await store().query_stats(streams, {
|
|
1434
|
+
exclude: [SNAP_EVENT, TOMBSTONE_EVENT]
|
|
1435
|
+
});
|
|
1433
1436
|
const true_heads = await store().query_stats(streams, {});
|
|
1434
1437
|
const out = /* @__PURE__ */ new Map();
|
|
1435
|
-
for (const [stream, { head }] of
|
|
1436
|
-
|
|
1438
|
+
for (const [stream, { head }] of domain_heads) {
|
|
1439
|
+
const marker_head = stats.get(stream)?.head;
|
|
1440
|
+
const interrupted = marker_head?.name === TOMBSTONE_EVENT;
|
|
1437
1441
|
out.set(stream, {
|
|
1438
1442
|
max_id: head.id,
|
|
1439
1443
|
version: true_heads.get(stream).head.version,
|
|
1440
|
-
last_event_name: head.name
|
|
1444
|
+
last_event_name: head.name,
|
|
1445
|
+
...interrupted ? { resumed_guard: { id: marker_head.id } } : {}
|
|
1441
1446
|
});
|
|
1442
1447
|
}
|
|
1443
1448
|
return out;
|
|
@@ -1486,6 +1491,11 @@ async function guard_with_tombstones(safe, stream_info, correlation, tombstone2,
|
|
|
1486
1491
|
await Promise.all(
|
|
1487
1492
|
safe.map(async (stream) => {
|
|
1488
1493
|
const info = stream_info.get(stream);
|
|
1494
|
+
if (info.resumed_guard) {
|
|
1495
|
+
guarded.push(stream);
|
|
1496
|
+
guard_events.set(stream, { id: info.resumed_guard.id, stream });
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1489
1499
|
const committed = await tombstone2(stream, info.version, correlation);
|
|
1490
1500
|
if (committed) {
|
|
1491
1501
|
guarded.push(stream);
|
|
@@ -1563,6 +1573,8 @@ var DEFAULT_COLD_START_BACK_SCAN = 1e4;
|
|
|
1563
1573
|
var CorrelateCycle = class {
|
|
1564
1574
|
_checkpoint = -1;
|
|
1565
1575
|
_initialized = false;
|
|
1576
|
+
/** In-flight init, memoized for single-flight and cleared on failure. */
|
|
1577
|
+
_init_promise;
|
|
1566
1578
|
_timer = void 0;
|
|
1567
1579
|
// target → the priority it was last subscribed at. A dynamic target is
|
|
1568
1580
|
// re-subscribed (so the store's `GREATEST` upsert runs) only when a later
|
|
@@ -1645,7 +1657,16 @@ var CorrelateCycle = class {
|
|
|
1645
1657
|
*/
|
|
1646
1658
|
async init() {
|
|
1647
1659
|
if (this._initialized) return;
|
|
1660
|
+
if (!this._init_promise) {
|
|
1661
|
+
this._init_promise = this._run_init().catch((error) => {
|
|
1662
|
+
this._init_promise = void 0;
|
|
1663
|
+
throw error;
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
await this._init_promise;
|
|
1648
1667
|
this._initialized = true;
|
|
1668
|
+
}
|
|
1669
|
+
async _run_init() {
|
|
1649
1670
|
const { watermark } = await store().subscribe([...this._static_targets]);
|
|
1650
1671
|
this._checkpoint = this._has_dynamic_resolvers ? Math.max(-1, watermark - this._cold_start_back_scan) : watermark;
|
|
1651
1672
|
this._on_init?.();
|
|
@@ -1654,6 +1675,26 @@ var CorrelateCycle = class {
|
|
|
1654
1675
|
}
|
|
1655
1676
|
await this._on_init_async?.();
|
|
1656
1677
|
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Forget targets whose subscription rows no longer exist, so a later
|
|
1680
|
+
* scan can re-subscribe them.
|
|
1681
|
+
*
|
|
1682
|
+
* A full close deletes the closed stream's subscription row. The
|
|
1683
|
+
* in-process dedup would otherwise still believe the target is
|
|
1684
|
+
* subscribed and never re-issue `subscribe()`, silently stopping
|
|
1685
|
+
* delivery for any reaction whose target is named after the stream —
|
|
1686
|
+
* the documented per-aggregate shape `.to(e => ({target: e.stream}))`
|
|
1687
|
+
* makes those two namespaces collide by construction (#1398).
|
|
1688
|
+
*
|
|
1689
|
+
* Static targets are left alone: they are subscribed once at init and
|
|
1690
|
+
* recorded at +Infinity so the dynamic path never re-opens them.
|
|
1691
|
+
*/
|
|
1692
|
+
forget_subscribed(streams) {
|
|
1693
|
+
const statics = new Set(this._static_targets.map((t) => t.stream));
|
|
1694
|
+
for (const stream of streams) {
|
|
1695
|
+
if (!statics.has(stream)) this._subscribed.delete(stream);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1657
1698
|
/**
|
|
1658
1699
|
* Discover dynamic-resolver targets in the events past the checkpoint
|
|
1659
1700
|
* and register any new streams via `cd.subscribe`. Static targets are
|
|
@@ -3276,6 +3317,7 @@ var Act = class {
|
|
|
3276
3317
|
correlation: close_correlation(this._correlator, close_actor),
|
|
3277
3318
|
with_stream_lock: (stream, work) => this._with_close_lock(stream, work)
|
|
3278
3319
|
});
|
|
3320
|
+
this._forget_closed_subscriptions(result);
|
|
3279
3321
|
try {
|
|
3280
3322
|
this.emit("closed", result);
|
|
3281
3323
|
} catch (err) {
|
|
@@ -4270,6 +4312,15 @@ var Act = class {
|
|
|
4270
4312
|
* ]);
|
|
4271
4313
|
* ```
|
|
4272
4314
|
*/
|
|
4315
|
+
/**
|
|
4316
|
+
* After a close, forget any target whose subscription row the truncate
|
|
4317
|
+
* removed, so a later correlate can re-subscribe it (#1398). Restart
|
|
4318
|
+
* targets keep their row, so only fully-retired streams are forgotten.
|
|
4319
|
+
*/
|
|
4320
|
+
_forget_closed_subscriptions(result) {
|
|
4321
|
+
const retired = [...result.truncated.entries()].filter(([, r]) => r.committed.name === TOMBSTONE_EVENT).map(([stream]) => stream);
|
|
4322
|
+
if (retired.length) this._correlate.forget_subscribed(retired);
|
|
4323
|
+
}
|
|
4273
4324
|
async close(targets) {
|
|
4274
4325
|
if (!targets.length) return { truncated: /* @__PURE__ */ new Map(), skipped: [] };
|
|
4275
4326
|
return this._scoped(async () => {
|
|
@@ -4284,6 +4335,7 @@ var Act = class {
|
|
|
4284
4335
|
correlation: close_correlation(this._correlator, close_actor),
|
|
4285
4336
|
with_stream_lock: (stream, work) => this._with_close_lock(stream, work)
|
|
4286
4337
|
});
|
|
4338
|
+
this._forget_closed_subscriptions(result);
|
|
4287
4339
|
this.emit("closed", result);
|
|
4288
4340
|
return result;
|
|
4289
4341
|
});
|