@rotorsoft/act 0.43.0 → 0.45.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.
Files changed (44) hide show
  1. package/README.md +87 -379
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/@types/act.d.ts +43 -5
  4. package/dist/@types/act.d.ts.map +1 -1
  5. package/dist/@types/adapters/console-logger.d.ts.map +1 -1
  6. package/dist/@types/adapters/in-memory-store.d.ts +22 -2
  7. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
  8. package/dist/@types/builders/act-builder.d.ts +33 -9
  9. package/dist/@types/builders/act-builder.d.ts.map +1 -1
  10. package/dist/@types/builders/slice-builder.d.ts +23 -8
  11. package/dist/@types/builders/slice-builder.d.ts.map +1 -1
  12. package/dist/@types/internal/build-classify.d.ts +20 -0
  13. package/dist/@types/internal/build-classify.d.ts.map +1 -1
  14. package/dist/@types/internal/correlate-cycle.d.ts +1 -0
  15. package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
  16. package/dist/@types/internal/drain-cycle.d.ts +43 -3
  17. package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
  18. package/dist/@types/internal/drain.d.ts +3 -1
  19. package/dist/@types/internal/drain.d.ts.map +1 -1
  20. package/dist/@types/internal/index.d.ts +3 -2
  21. package/dist/@types/internal/index.d.ts.map +1 -1
  22. package/dist/@types/internal/reactions.d.ts.map +1 -1
  23. package/dist/@types/internal/tracing.d.ts +51 -0
  24. package/dist/@types/internal/tracing.d.ts.map +1 -1
  25. package/dist/@types/ports.d.ts +10 -0
  26. package/dist/@types/ports.d.ts.map +1 -1
  27. package/dist/@types/test/sandbox.d.ts +1 -1
  28. package/dist/@types/test/sandbox.d.ts.map +1 -1
  29. package/dist/@types/types/ports.d.ts +203 -2
  30. package/dist/@types/types/ports.d.ts.map +1 -1
  31. package/dist/@types/types/reaction.d.ts +20 -2
  32. package/dist/@types/types/reaction.d.ts.map +1 -1
  33. package/dist/{chunk-QAB4SDOS.js → chunk-PGTC7VOC.js} +117 -11
  34. package/dist/chunk-PGTC7VOC.js.map +1 -0
  35. package/dist/index.cjs +1217 -897
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.js +1108 -893
  38. package/dist/index.js.map +1 -1
  39. package/dist/test/index.cjs +116 -11
  40. package/dist/test/index.cjs.map +1 -1
  41. package/dist/test/index.js +3 -3
  42. package/dist/test/index.js.map +1 -1
  43. package/package.json +2 -2
  44. package/dist/chunk-QAB4SDOS.js.map +0 -1
@@ -3831,7 +3831,7 @@ function manageArtifactAttachment(attachment) {
3831
3831
  }
3832
3832
  }
3833
3833
 
3834
- // ../../node_modules/.pnpm/vite@7.3.3_@types+node@25.7.0_jiti@2.6.1_lightningcss@1.32.0_terser@5.46.1_tsx@4.22.0_yaml@2.9.0/node_modules/vite/dist/node/module-runner.js
3834
+ // ../../node_modules/.pnpm/vite@7.3.3_@types+node@25.8.0_jiti@2.6.1_lightningcss@1.32.0_terser@5.46.1_tsx@4.22.2_yaml@2.9.0/node_modules/vite/dist/node/module-runner.js
3835
3835
  var SOURCEMAPPING_URL = "sourceMa";
3836
3836
  SOURCEMAPPING_URL += "ppingURL";
3837
3837
  var isWindows = typeof process < "u" && process.platform === "win32";
@@ -3876,7 +3876,7 @@ var envProxy = new Proxy({}, { get(_, p) {
3876
3876
  throw Error(`[module runner] Dynamic access of "import.meta.env" is not supported. Please, use "import.meta.env.${String(p)}" instead.`);
3877
3877
  } });
3878
3878
 
3879
- // ../../node_modules/.pnpm/vitest@4.1.6_@opentelemetry+api@1.9.0_@types+node@25.7.0_@vitest+coverage-v8@4.1.6_vite_e55bbfcaf248f5e226d3dcf8ee1c3ee4/node_modules/vitest/dist/index.js
3879
+ // ../../node_modules/.pnpm/vitest@4.1.6_@opentelemetry+api@1.9.0_@types+node@25.8.0_@vitest+coverage-v8@4.1.6_vite_a70b8d74610499979bc2a6e2324eab21/node_modules/vitest/dist/index.js
3880
3880
  var import_expect_type = __toESM(require_dist(), 1);
3881
3881
 
3882
3882
  // src/internal/lru-map.ts
@@ -4021,6 +4021,12 @@ var ConsoleLogger = class _ConsoleLogger {
4021
4021
  if (typeof objOrMsg === "string") {
4022
4022
  message = objOrMsg;
4023
4023
  obj = {};
4024
+ } else if (objOrMsg instanceof Error) {
4025
+ message = msg ?? objOrMsg.message;
4026
+ obj = {
4027
+ error: { message: objOrMsg.message, name: objOrMsg.name },
4028
+ stack: objOrMsg.stack
4029
+ };
4024
4030
  } else if (objOrMsg !== null && typeof objOrMsg === "object") {
4025
4031
  message = msg;
4026
4032
  obj = { ...objOrMsg };
@@ -4051,6 +4057,9 @@ var ConsoleLogger = class _ConsoleLogger {
4051
4057
  let data;
4052
4058
  if (typeof objOrMsg === "string") {
4053
4059
  message = objOrMsg;
4060
+ } else if (objOrMsg instanceof Error) {
4061
+ message = msg ?? objOrMsg.message;
4062
+ data = objOrMsg.stack;
4054
4063
  } else {
4055
4064
  message = msg ?? "";
4056
4065
  if (objOrMsg !== void 0 && objOrMsg !== null) {
@@ -4266,13 +4275,15 @@ var _cache = port(function cache(adapter) {
4266
4275
  });
4267
4276
  var SNAP_EVENT = "__snapshot__";
4268
4277
  var TOMBSTONE_EVENT = "__tombstone__";
4278
+ var DEFAULT_LANE = "default";
4269
4279
 
4270
4280
  // src/adapters/in-memory-store.ts
4271
4281
  var InMemoryStream = class {
4272
- constructor(stream, source, priority = 0) {
4282
+ constructor(stream, source, priority = 0, lane = DEFAULT_LANE) {
4273
4283
  this.stream = stream;
4274
4284
  this.source = source;
4275
4285
  this._priority = priority;
4286
+ this._lane = lane;
4276
4287
  }
4277
4288
  _at = -1;
4278
4289
  _retry = -1;
@@ -4281,9 +4292,17 @@ var InMemoryStream = class {
4281
4292
  _leased_by = void 0;
4282
4293
  _leased_until = void 0;
4283
4294
  _priority = 0;
4295
+ _lane = DEFAULT_LANE;
4284
4296
  get priority() {
4285
4297
  return this._priority;
4286
4298
  }
4299
+ get lane() {
4300
+ return this._lane;
4301
+ }
4302
+ /** Replace on every subscribe — current builder config wins on restart. */
4303
+ set lane(value) {
4304
+ this._lane = value;
4305
+ }
4287
4306
  /**
4288
4307
  * Bump the priority via {@link subscribe}: keeps the maximum across
4289
4308
  * reactions so the highest-priority registrant wins.
@@ -4337,7 +4356,8 @@ var InMemoryStream = class {
4337
4356
  at: lease.at,
4338
4357
  by: lease.by,
4339
4358
  retry: this._retry,
4340
- lagging: lease.lagging
4359
+ lagging: lease.lagging,
4360
+ lane: this._lane
4341
4361
  };
4342
4362
  }
4343
4363
  /**
@@ -4356,7 +4376,8 @@ var InMemoryStream = class {
4356
4376
  at: this._at,
4357
4377
  by: lease.by,
4358
4378
  retry: this._retry,
4359
- lagging: lease.lagging
4379
+ lagging: lease.lagging,
4380
+ lane: this._lane
4360
4381
  };
4361
4382
  }
4362
4383
  }
@@ -4376,7 +4397,8 @@ var InMemoryStream = class {
4376
4397
  by: this._leased_by,
4377
4398
  retry: this._retry,
4378
4399
  error: this._error,
4379
- lagging: lease.lagging
4400
+ lagging: lease.lagging,
4401
+ lane: this._lane
4380
4402
  };
4381
4403
  }
4382
4404
  }
@@ -4552,7 +4574,7 @@ var InMemoryStore = class {
4552
4574
  * @param millis - Lease duration in milliseconds.
4553
4575
  * @returns Granted leases.
4554
4576
  */
4555
- async claim(lagging, leading, by, millis) {
4577
+ async claim(lagging, leading, by, millis, lane) {
4556
4578
  await sleep();
4557
4579
  const sourceRegex = /* @__PURE__ */ new Map();
4558
4580
  const getRegex = (source) => {
@@ -4573,7 +4595,7 @@ var InMemoryStore = class {
4573
4595
  return false;
4574
4596
  };
4575
4597
  const available = [...this._streams.values()].filter(
4576
- (s) => s.is_available && hasWork(s)
4598
+ (s) => s.is_available && hasWork(s) && (lane === void 0 || s.lane === lane)
4577
4599
  );
4578
4600
  const lag = available.sort((a, b2) => b2.priority - a.priority || a.at - b2.at).slice(0, lagging).map((s) => ({
4579
4601
  stream: s.stream,
@@ -4609,12 +4631,21 @@ var InMemoryStore = class {
4609
4631
  async subscribe(streams) {
4610
4632
  await sleep();
4611
4633
  let subscribed = 0;
4612
- for (const { stream, source, priority = 0 } of streams) {
4634
+ for (const {
4635
+ stream,
4636
+ source,
4637
+ priority = 0,
4638
+ lane = DEFAULT_LANE
4639
+ } of streams) {
4613
4640
  const existing = this._streams.get(stream);
4614
4641
  if (existing) {
4615
4642
  existing.bumpPriority(priority);
4643
+ existing.lane = lane;
4616
4644
  } else {
4617
- this._streams.set(stream, new InMemoryStream(stream, source, priority));
4645
+ this._streams.set(
4646
+ stream,
4647
+ new InMemoryStream(stream, source, priority, lane)
4648
+ );
4618
4649
  subscribed++;
4619
4650
  }
4620
4651
  }
@@ -4661,6 +4692,7 @@ var InMemoryStore = class {
4661
4692
  }
4662
4693
  if (filter.blocked !== void 0 && s.blocked !== filter.blocked)
4663
4694
  return false;
4695
+ if (filter.lane !== void 0 && s.lane !== filter.lane) return false;
4664
4696
  return true;
4665
4697
  };
4666
4698
  }
@@ -4771,6 +4803,7 @@ var InMemoryStore = class {
4771
4803
  continue;
4772
4804
  }
4773
4805
  if (blocked !== void 0 && s.blocked !== blocked) continue;
4806
+ if (query?.lane !== void 0 && s.lane !== query.lane) continue;
4774
4807
  callback({
4775
4808
  stream: s.stream,
4776
4809
  source: s.source,
@@ -4780,13 +4813,85 @@ var InMemoryStore = class {
4780
4813
  error: s.error,
4781
4814
  priority: s.priority,
4782
4815
  leased_by: s.leased_by,
4783
- leased_until: s.leased_until
4816
+ leased_until: s.leased_until,
4817
+ lane: s.lane
4784
4818
  });
4785
4819
  count++;
4786
4820
  if (count >= limit) break;
4787
4821
  }
4788
4822
  return { maxEventId: this._events.length - 1, count };
4789
4823
  }
4824
+ /**
4825
+ * Per-stream aggregated stats — see {@link Store.query_stats}.
4826
+ *
4827
+ * Single forward scan over the in-memory event list, accumulating per
4828
+ * stream. The "cheap heads" cost tier from durable adapters doesn't
4829
+ * apply here (InMemory has no indexes); correctness is the goal, perf
4830
+ * is a non-issue.
4831
+ *
4832
+ * Scope rules:
4833
+ * - Array `input` — explicit stream names, regardless of subscription.
4834
+ * - Filter `input` — `stream`/`stream_exact` match against event-bearing
4835
+ * stream names; `source`/`source_exact`/`blocked` require a
4836
+ * corresponding subscription in `_streams` (those are subscription
4837
+ * concepts, not event concepts). Empty filter `{}` matches every
4838
+ * event-bearing stream.
4839
+ */
4840
+ async query_stats(input, options) {
4841
+ await sleep();
4842
+ const exclude = new Set(options?.exclude ?? []);
4843
+ const wantTail = options?.tail ?? false;
4844
+ const wantCount = options?.count ?? false;
4845
+ const wantNames = options?.names ?? false;
4846
+ const before = options?.before;
4847
+ const arrayTargets = Array.isArray(input) ? new Set(input) : null;
4848
+ const filter = Array.isArray(input) ? null : input;
4849
+ const streamRe = filter?.stream && !filter.stream_exact ? new RegExp(filter.stream) : void 0;
4850
+ const scopeCache = /* @__PURE__ */ new Map();
4851
+ const inScope = (stream) => {
4852
+ const cached = scopeCache.get(stream);
4853
+ if (cached !== void 0) return cached;
4854
+ let ok = true;
4855
+ if (arrayTargets) {
4856
+ ok = arrayTargets.has(stream);
4857
+ } else if (filter?.stream !== void 0) {
4858
+ ok = filter.stream_exact ? stream === filter.stream : (
4859
+ // biome-ignore lint/style/noNonNullAssertion: streamRe set when stream is regex
4860
+ streamRe.test(stream)
4861
+ );
4862
+ }
4863
+ scopeCache.set(stream, ok);
4864
+ return ok;
4865
+ };
4866
+ const acc = /* @__PURE__ */ new Map();
4867
+ for (const e of this._events) {
4868
+ if (before !== void 0 && e.id >= before) continue;
4869
+ if (!inScope(e.stream)) continue;
4870
+ if (exclude.has(e.name)) continue;
4871
+ let a = acc.get(e.stream);
4872
+ if (!a) {
4873
+ a = { head: e, count: 0 };
4874
+ if (wantTail) a.tail = e;
4875
+ if (wantNames) a.names = {};
4876
+ acc.set(e.stream, a);
4877
+ }
4878
+ a.head = e;
4879
+ a.count++;
4880
+ if (wantNames) {
4881
+ const n = String(e.name);
4882
+ a.names[n] = (a.names[n] ?? 0) + 1;
4883
+ }
4884
+ }
4885
+ const out = /* @__PURE__ */ new Map();
4886
+ for (const [stream, a] of acc) {
4887
+ const stats = { head: a.head };
4888
+ if (wantTail) stats.tail = a.tail;
4889
+ if (wantCount) stats.count = a.count;
4890
+ if (wantNames) stats.names = a.names;
4891
+ out.set(stream, stats);
4892
+ }
4893
+ return out;
4894
+ }
4790
4895
  /**
4791
4896
  * Atomically truncates streams and seeds each with a snapshot or tombstone.
4792
4897
  * @param targets - Streams to truncate with optional snapshot state and meta.