@rotorsoft/act 1.30.0 → 1.31.1

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.
@@ -670,6 +670,16 @@ var InMemoryStore = class {
670
670
  _streams = /* @__PURE__ */ new Map();
671
671
  /** Correlate checkpoint (#1484): how far the log has been READ. */
672
672
  _correlated_at = -1;
673
+ /**
674
+ * Per-correlator checkpoint and lease (#1532), keyed by correlator.
675
+ *
676
+ * Keyed rather than singular because correlators that look for different
677
+ * things read the log for different reasons: sharing one position lets a
678
+ * partial-behaviour worker inherit another's, and sharing one lease lets
679
+ * one starve the other. Callers that supply no correlator use
680
+ * `_correlated_at` instead, which is the pre-#1532 behaviour.
681
+ */
682
+ _correlators = /* @__PURE__ */ new Map();
673
683
  // last committed version per stream — O(1) replacement for filter-on-commit
674
684
  _stream_versions = /* @__PURE__ */ new Map();
675
685
  // max non-snapshot event id per stream — drives the has-work probe in
@@ -908,10 +918,33 @@ var InMemoryStore = class {
908
918
  * @param streams - Streams to register with optional source + priority.
909
919
  * @returns subscribed count and current max watermark.
910
920
  */
911
- async subscribe(streams, correlated_at) {
912
- if (correlated_at !== void 0 && correlated_at > this._correlated_at)
913
- this._correlated_at = correlated_at;
921
+ async subscribe(streams, correlated_at, correlator) {
914
922
  await sleep();
923
+ let correlating;
924
+ let keyed_at;
925
+ if (correlator) {
926
+ const now = Date.now();
927
+ const held = this._correlators.get(correlator.key);
928
+ const at = Math.max(held?.at ?? this._correlated_at, correlated_at ?? -1);
929
+ keyed_at = at;
930
+ if (!held || held.until < now || held.by === correlator.by) {
931
+ correlating = true;
932
+ this._correlators.set(correlator.key, {
933
+ at,
934
+ by: correlator.by,
935
+ // A non-positive `millis` releases outright rather than setting an
936
+ // expiry a hair in the future: a successor asking inside the same
937
+ // millisecond would otherwise still be refused.
938
+ until: correlator.millis > 0 ? now + correlator.millis : 0
939
+ });
940
+ } else {
941
+ correlating = false;
942
+ held.at = at;
943
+ }
944
+ if (correlated_at !== void 0 && correlated_at > this._correlated_at)
945
+ this._correlated_at = correlated_at;
946
+ } else if (correlated_at !== void 0 && correlated_at > this._correlated_at)
947
+ this._correlated_at = correlated_at;
915
948
  let subscribed = 0;
916
949
  for (const {
917
950
  stream,
@@ -936,7 +969,12 @@ var InMemoryStore = class {
936
969
  for (const s of this._streams.values()) {
937
970
  if (s.at > watermark) watermark = s.at;
938
971
  }
939
- return { subscribed, watermark, correlated_at: this._correlated_at };
972
+ return {
973
+ subscribed,
974
+ watermark,
975
+ correlated_at: keyed_at ?? this._correlated_at,
976
+ ...correlating === void 0 ? {} : { correlating }
977
+ };
940
978
  }
941
979
  /**
942
980
  * Acknowledge completion of processing for leased streams.