@rotorsoft/act 1.22.2 → 1.22.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/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  sleep,
20
20
  store,
21
21
  validate
22
- } from "./chunk-KBTC3NGQ.js";
22
+ } from "./chunk-2FN4RFBQ.js";
23
23
  import {
24
24
  ActorSchema,
25
25
  CausationEventSchema,
@@ -1381,13 +1381,22 @@ var CorrelateCycle = class {
1381
1381
  _has_dynamic_resolvers;
1382
1382
  _cd;
1383
1383
  _on_init;
1384
- constructor(registry, static_targets, has_dynamic_resolvers, cd, maxSubscribedStreams, on_init) {
1384
+ /**
1385
+ * Scope runner (#1191). The periodic `start_polling` timer fires
1386
+ * outside any caller frame, so its `correlate()` must be re-wrapped in
1387
+ * the Act's `_scoped` bag or `store()`/`cache()` resolve to the
1388
+ * singleton for a scoped Act. The orchestrator always threads its
1389
+ * `_scoped` (identity for a non-scoped Act), so it's required.
1390
+ */
1391
+ _run_scoped;
1392
+ constructor(registry, static_targets, has_dynamic_resolvers, cd, maxSubscribedStreams, on_init, run_scoped) {
1385
1393
  this._subscribed = new LruSet(maxSubscribedStreams);
1386
1394
  this._registry = registry;
1387
1395
  this._static_targets = static_targets;
1388
1396
  this._has_dynamic_resolvers = has_dynamic_resolvers;
1389
1397
  this._cd = cd;
1390
1398
  this._on_init = on_init;
1399
+ this._run_scoped = run_scoped;
1391
1400
  }
1392
1401
  /** Last correlated event id. */
1393
1402
  get checkpoint() {
@@ -1482,7 +1491,9 @@ var CorrelateCycle = class {
1482
1491
  if (this._timer) return false;
1483
1492
  const limit = query.limit || 100;
1484
1493
  this._timer = setInterval(
1485
- () => this.correlate({ ...query, after: this._checkpoint, limit }).then((result) => {
1494
+ () => this._run_scoped(
1495
+ () => this.correlate({ ...query, after: this._checkpoint, limit })
1496
+ ).then((result) => {
1486
1497
  if (callback && result.subscribed) callback(result.subscribed);
1487
1498
  }).catch((err) => log().error(err)),
1488
1499
  frequency
@@ -1787,12 +1798,15 @@ async function scan(source, opts = {}, callback) {
1787
1798
  const new_caused_by = id_map.get(caused_by);
1788
1799
  if (new_caused_by !== void 0 && new_caused_by !== caused_by) {
1789
1800
  remapped = {
1790
- ...event,
1801
+ ...migrated,
1791
1802
  meta: {
1792
- ...event.meta,
1803
+ ...migrated.meta,
1793
1804
  causation: {
1794
- ...event.meta.causation,
1795
- event: { ...event.meta.causation.event, id: new_caused_by }
1805
+ ...migrated.meta.causation,
1806
+ event: {
1807
+ ...migrated.meta.causation.event,
1808
+ id: new_caused_by
1809
+ }
1796
1810
  }
1797
1811
  }
1798
1812
  };
@@ -1859,7 +1873,8 @@ async function load(me, target, callback) {
1859
1873
  ...cached ? { after: cached.event_id } : { with_snaps: true, ...asOf }
1860
1874
  }
1861
1875
  );
1862
- if (replayed > 0 && !time_travel && event && !me.pii_aware) {
1876
+ const head_is_tombstone = event?.name === TOMBSTONE_EVENT;
1877
+ if (replayed > 0 && !time_travel && event && !me.pii_aware && !head_is_tombstone) {
1863
1878
  await cache().set(stream, {
1864
1879
  stream,
1865
1880
  state: state2,
@@ -2293,8 +2308,9 @@ var DrainController = class {
2293
2308
  */
2294
2309
  start(cycleMs) {
2295
2310
  if (this._worker || this._stopped) return;
2311
+ const run = this._deps.run_scoped;
2296
2312
  const tick = async () => {
2297
- if (this._armed) await this.drain();
2313
+ if (this._armed) await run(() => this.drain());
2298
2314
  if (this._stopped) return;
2299
2315
  this._worker = setTimeout(tick, cycleMs);
2300
2316
  this._worker.unref();
@@ -2895,6 +2911,9 @@ var Act = class {
2895
2911
  this.emit("closed", result);
2896
2912
  },
2897
2913
  breaker: this._breaker,
2914
+ // Re-scope the per-lane worker's auto-start ticks so their drain
2915
+ // resolves the scoped ports, not the singleton (#1191).
2916
+ run_scoped: this._scoped,
2898
2917
  // Pass lane only when a true per-lane controller is active.
2899
2918
  // The all-lanes (single default) case keeps lane=undefined so
2900
2919
  // adapter SQL collapses to the single-lane shape.
@@ -2941,14 +2960,21 @@ var Act = class {
2941
2960
  options.maxSubscribedStreams ?? DEFAULT_MAX_SUBSCRIBED_STREAMS,
2942
2961
  () => {
2943
2962
  if (this._drain && this._reactive_events.size > 0) this._arm_all();
2944
- }
2963
+ },
2964
+ // Re-scope the background `start_correlations` timer so its
2965
+ // correlate resolves the scoped ports, not the singleton (#1191).
2966
+ this._scoped
2945
2967
  );
2946
2968
  }
2947
2969
  /** Settle loop driving correlate + drain to quiescence. */
2948
2970
  _build_settle(options) {
2949
2971
  return new SettleLoop(
2950
2972
  {
2951
- init: () => this._correlate.init(),
2973
+ // Scope the init like every other store-touching path — a bare
2974
+ // `this._correlate.init()` runs `store().subscribe(...)` against
2975
+ // the singleton for a scoped Act, so static targets never land on
2976
+ // the scoped store and `_initialized` then blocks a retry (#1191).
2977
+ init: () => this._scoped(() => this._correlate.init()),
2952
2978
  checkpoint: () => this._correlate.checkpoint,
2953
2979
  correlate: (q) => this.correlate(q),
2954
2980
  drain: (o) => this.drain(o),