@rotorsoft/act 1.32.26 → 1.32.27

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 (47) hide show
  1. package/README.md +2 -3
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/@types/act.d.ts +5 -151
  4. package/dist/@types/act.d.ts.map +1 -1
  5. package/dist/@types/adapters/in-memory-store.d.ts +0 -21
  6. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
  7. package/dist/@types/builders/act-builder.d.ts +0 -25
  8. package/dist/@types/builders/act-builder.d.ts.map +1 -1
  9. package/dist/@types/builders/build-classify.d.ts +4 -4
  10. package/dist/@types/builders/build-classify.d.ts.map +1 -1
  11. package/dist/@types/builders/projection-builder.d.ts.map +1 -1
  12. package/dist/@types/builders/slice-builder.d.ts +1 -12
  13. package/dist/@types/builders/slice-builder.d.ts.map +1 -1
  14. package/dist/@types/builders/state-builder.d.ts +0 -189
  15. package/dist/@types/builders/state-builder.d.ts.map +1 -1
  16. package/dist/@types/config.d.ts +0 -27
  17. package/dist/@types/config.d.ts.map +1 -1
  18. package/dist/@types/internal/close-cycle.d.ts +2 -1
  19. package/dist/@types/internal/close-cycle.d.ts.map +1 -1
  20. package/dist/@types/ports.d.ts +0 -7
  21. package/dist/@types/ports.d.ts.map +1 -1
  22. package/dist/@types/test/sandbox.d.ts +0 -14
  23. package/dist/@types/test/sandbox.d.ts.map +1 -1
  24. package/dist/@types/types/action.d.ts +0 -27
  25. package/dist/@types/types/action.d.ts.map +1 -1
  26. package/dist/@types/types/errors.d.ts +1 -92
  27. package/dist/@types/types/errors.d.ts.map +1 -1
  28. package/dist/@types/types/ports.d.ts +0 -70
  29. package/dist/@types/types/ports.d.ts.map +1 -1
  30. package/dist/@types/types/reaction.d.ts +0 -33
  31. package/dist/@types/types/reaction.d.ts.map +1 -1
  32. package/dist/{chunk-QXW3JV2H.js → chunk-5FXT63KF.js} +2 -2
  33. package/dist/chunk-5FXT63KF.js.map +1 -0
  34. package/dist/{chunk-XSG2NW4J.js → chunk-F7K7SIG6.js} +1 -1
  35. package/dist/chunk-F7K7SIG6.js.map +1 -0
  36. package/dist/index.cjs +22 -159
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.js +24 -161
  39. package/dist/index.js.map +1 -1
  40. package/dist/test/index.cjs.map +1 -1
  41. package/dist/test/index.js +2 -2
  42. package/dist/test/index.js.map +1 -1
  43. package/dist/types/index.cjs.map +1 -1
  44. package/dist/types/index.js +1 -1
  45. package/package.json +1 -4
  46. package/dist/chunk-QXW3JV2H.js.map +0 -1
  47. package/dist/chunk-XSG2NW4J.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1406,10 +1406,8 @@ var ALL_LANES = /* @__PURE__ */ Symbol("act-1103/all-lanes");
1406
1406
  function classify_registry(registry, states) {
1407
1407
  const statics = /* @__PURE__ */ new Map();
1408
1408
  const target_lanes = /* @__PURE__ */ new Map();
1409
- const reactive_events = /* @__PURE__ */ new Set();
1410
1409
  const event_to_lanes = /* @__PURE__ */ new Map();
1411
1410
  for (const [name, register] of Object.entries(registry.events)) {
1412
- if (register.reactions.size > 0) reactive_events.add(name);
1413
1411
  for (const reaction of register.reactions.values()) {
1414
1412
  if (typeof reaction.resolver === "function") {
1415
1413
  event_to_lanes.set(name, ALL_LANES);
@@ -1447,7 +1445,6 @@ function classify_registry(registry, states) {
1447
1445
  }
1448
1446
  return {
1449
1447
  static_targets: [...statics.values()],
1450
- reactive_events,
1451
1448
  event_to_state,
1452
1449
  event_to_lanes
1453
1450
  };
@@ -2604,7 +2601,7 @@ async function run_full_closes(full, target_map, deps, skipped) {
2604
2601
  }
2605
2602
  const safe = await partition_by_safety(
2606
2603
  stream_info,
2607
- deps.reactive_events_size,
2604
+ deps.reactive,
2608
2605
  skipped,
2609
2606
  deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE,
2610
2607
  deps.catch_up_correlation
@@ -2641,8 +2638,8 @@ async function run_full_closes(full, target_map, deps, skipped) {
2641
2638
  );
2642
2639
  }
2643
2640
  async function run_windowed_closes(windowed, deps, skipped) {
2644
- const checkpoint = deps.reactive_events_size > 0 ? await deps.catch_up_correlation(Number.MAX_SAFE_INTEGER) : -1;
2645
- const min_at = deps.reactive_events_size > 0 ? await probe_min_watermarks(
2641
+ const checkpoint = deps.reactive ? await deps.catch_up_correlation(Number.MAX_SAFE_INTEGER) : -1;
2642
+ const min_at = deps.reactive ? await probe_min_watermarks(
2646
2643
  windowed.map((t) => t.stream),
2647
2644
  deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE,
2648
2645
  checkpoint
@@ -2730,8 +2727,8 @@ async function scan_stream_heads(streams) {
2730
2727
  }
2731
2728
  return out;
2732
2729
  }
2733
- async function partition_by_safety(stream_info, reactive_events_size, skipped, page_size, catch_up_correlation2) {
2734
- if (reactive_events_size === 0) return [...stream_info.keys()];
2730
+ async function partition_by_safety(stream_info, reactive, skipped, page_size, catch_up_correlation2) {
2731
+ if (!reactive) return [...stream_info.keys()];
2735
2732
  let needed = -1;
2736
2733
  for (const info of stream_info.values())
2737
2734
  needed = Math.max(needed, info.max_id);
@@ -4589,7 +4586,8 @@ var Act = class {
4589
4586
  _breaker;
4590
4587
  _listen;
4591
4588
  _drain;
4592
- _reactive_events;
4589
+ /** Whether any event has a reaction; nothing arms without one. */
4590
+ _reactive;
4593
4591
  _drain_controllers;
4594
4592
  _correlate;
4595
4593
  _settle;
@@ -4719,7 +4717,7 @@ var Act = class {
4719
4717
  });
4720
4718
  this._handle_batch = build_handle_batch(this._logger);
4721
4719
  const classification = classify_registry(this.registry, this._states);
4722
- this._reactive_events = classification.reactive_events;
4720
+ this._reactive = classification.event_to_lanes.size > 0;
4723
4721
  this._event_to_state = classification.event_to_state;
4724
4722
  this._event_to_lanes = classification.event_to_lanes;
4725
4723
  this._listen = options.listen !== false;
@@ -4826,9 +4824,8 @@ var Act = class {
4826
4824
  declared_lanes: new Set(this._declared_lanes),
4827
4825
  // Built after the controllers, so their keys are the active lanes.
4828
4826
  shard: this._drain_controllers.size < this._declared_lanes.length ? [...this._drain_controllers.keys()] : void 0,
4829
- on_init: () => {
4830
- if (this._drain && this._reactive_events.size > 0) this._arm_all();
4831
- },
4827
+ // Only reached on a draining app: writer-only ones never correlate.
4828
+ on_init: () => this._arm_all(),
4832
4829
  on_init_async: this._drain ? () => this._seed_persisted_defers() : void 0
4833
4830
  });
4834
4831
  }
@@ -4925,7 +4922,7 @@ var Act = class {
4925
4922
  }
4926
4923
  /** Failures are logged, never thrown: `notify` is a hint. */
4927
4924
  async _wire_notify(s) {
4928
- if (this._reactive_events.size === 0) return void 0;
4925
+ if (!this._reactive) return void 0;
4929
4926
  if (!s.notify) return void 0;
4930
4927
  if (!this._listen) return void 0;
4931
4928
  try {
@@ -4985,46 +4982,6 @@ var Act = class {
4985
4982
  * console.log(snapshots[0].state.count); // Current count after increment
4986
4983
  * ```
4987
4984
  *
4988
- * @example With error handling
4989
- * ```typescript
4990
- * try {
4991
- * await app.do(
4992
- * "withdraw",
4993
- * { stream: "account-123", actor: { id: "user1", name: "Alice" } },
4994
- * { amount: 1000 }
4995
- * );
4996
- * } catch (error) {
4997
- * if (error instanceof InvariantError) {
4998
- * console.error("Business rule violated:", error.description);
4999
- * } else if (error instanceof ConcurrencyError) {
5000
- * console.error("Concurrent modification detected, retry...");
5001
- * } else if (error instanceof ValidationError) {
5002
- * console.error("Invalid payload:", error.details);
5003
- * }
5004
- * }
5005
- * ```
5006
- *
5007
- * @example Reaction triggering another action (reactingTo auto-injected)
5008
- * ```typescript
5009
- * const app = act()
5010
- * .withState(Order)
5011
- * .withState(Inventory)
5012
- * .on("OrderPlaced")
5013
- * .do(async function reduceInventory(event, _stream, app) {
5014
- * // Inside reaction handlers, reactingTo is auto-injected when omitted.
5015
- * // The triggering event is used by default, maintaining the correlation chain.
5016
- * await app.do(
5017
- * "reduceStock",
5018
- * { stream: "inventory-1", actor: { id: "sys", name: "system" } },
5019
- * { amount: event.data.items.length }
5020
- * );
5021
- * // To use a different correlation, pass reactingTo explicitly:
5022
- * // await app.do("reduceStock", target, payload, { reactingTo: customEvent });
5023
- * })
5024
- * .to("inventory-1")
5025
- * .build();
5026
- * ```
5027
- *
5028
4985
  * @see {@link Target} for target structure
5029
4986
  * @see {@link Snapshot} for return value structure
5030
4987
  * @see {@link ValidationError}, {@link InvariantError}, {@link ConcurrencyError}
@@ -5040,10 +4997,9 @@ var Act = class {
5040
4997
  payload,
5041
4998
  do_options
5042
4999
  );
5043
- if (this._reactive_events.size > 0)
5044
- this._arm_for_event_names(
5045
- snapshots.map((s) => s.event.name)
5046
- );
5000
+ this._arm_for_event_names(
5001
+ snapshots.map((s) => s.event.name)
5002
+ );
5047
5003
  this.emit("committed", snapshots);
5048
5004
  return snapshots;
5049
5005
  });
@@ -5090,26 +5046,6 @@ var Act = class {
5090
5046
  * console.log(`Found ${count} events from ${first?.id} to ${last?.id}`);
5091
5047
  * ```
5092
5048
  *
5093
- * @example Query specific event types
5094
- * ```typescript
5095
- * const { count } = await app.query(
5096
- * { name: "UserCreated", limit: 100 },
5097
- * (event) => {
5098
- * console.log("User created:", event.data.email);
5099
- * }
5100
- * );
5101
- * ```
5102
- *
5103
- * @example Query events in time range
5104
- * ```typescript
5105
- * const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
5106
- * const { count } = await app.query({
5107
- * created_after: yesterday,
5108
- * stream: "user-123"
5109
- * });
5110
- * console.log(`User had ${count} events in last 24 hours`);
5111
- * ```
5112
- *
5113
5049
  * @see {@link query_array} for loading events into memory
5114
5050
  */
5115
5051
  async query(query, callback) {
@@ -5141,14 +5077,6 @@ var Act = class {
5141
5077
  * events.forEach(event => console.log(event.name, event.data));
5142
5078
  * ```
5143
5079
  *
5144
- * @example Get recent events
5145
- * ```typescript
5146
- * const recent = await app.query_array({
5147
- * stream: "user-123",
5148
- * limit: 10
5149
- * });
5150
- * ```
5151
- *
5152
5080
  * @see {@link query} for large result sets
5153
5081
  */
5154
5082
  async query_array(query) {
@@ -5219,12 +5147,6 @@ var Act = class {
5219
5147
  * await app.drain();
5220
5148
  * ```
5221
5149
  *
5222
- * @example In production, prefer settle()
5223
- * ```typescript
5224
- * await app.do("CreateItem", target, input);
5225
- * app.settle(); // debounced correlate→drain, emits "settled"
5226
- * ```
5227
- *
5228
5150
  * @see {@link settle} for debounced correlate→drain with lifecycle events
5229
5151
  * @see {@link correlate} for dynamic stream discovery
5230
5152
  * @see {@link start_correlations} for automatic correlation
@@ -5236,6 +5158,7 @@ var Act = class {
5236
5158
  return this._scoped(() => this._drain_all(options));
5237
5159
  }
5238
5160
  _arm_all() {
5161
+ if (!this._reactive) return;
5239
5162
  this._correlate.arm();
5240
5163
  for (const c of this._drain_controllers.values()) c.arm();
5241
5164
  }
@@ -5291,37 +5214,20 @@ var Act = class {
5291
5214
  * on reaction resolvers. It then registers these streams so they'll be picked up by
5292
5215
  * the next drain cycle.
5293
5216
  *
5294
- * @param query - Query filter to scan for new correlations
5295
5217
  * @param query - Scan filter — see {@link Query} for fields (typically
5296
5218
  * `{ after: <event-id>, limit: <count> }`)
5297
- * @returns Object with newly leased streams and last scanned event ID
5219
+ * @returns The number of newly subscribed streams and the last scanned event id
5298
5220
  *
5299
5221
  * @example Manual correlation
5300
5222
  * ```typescript
5301
5223
  * // Scan for new streams
5302
- * const { leased, last_id } = await app.correlate({ after: 0, limit: 100 });
5303
- * console.log(`Found ${leased.length} new streams`);
5224
+ * const { subscribed, last_id } = await app.correlate({ after: 0, limit: 100 });
5225
+ * console.log(`Subscribed ${subscribed} new streams`);
5304
5226
  *
5305
5227
  * // Save last_id for next scan
5306
5228
  * await saveCheckpoint(last_id);
5307
5229
  * ```
5308
5230
  *
5309
- * @example Dynamic stream creation
5310
- * ```typescript
5311
- * const app = act()
5312
- * .withState(User)
5313
- * .withState(UserStats)
5314
- * .on("UserLoggedIn")
5315
- * .do(async (event) => ["incrementLoginCount", {}])
5316
- * .to((event) => ({
5317
- * target: `stats-${event.stream}` // Dynamic target per user
5318
- * }))
5319
- * .build();
5320
- *
5321
- * // Discover stats streams as users log in
5322
- * await app.correlate();
5323
- * ```
5324
- *
5325
5231
  * @see {@link start_correlations} for automatic periodic correlation
5326
5232
  * @see {@link stop_correlations} to stop automatic correlation
5327
5233
  */
@@ -5334,8 +5240,7 @@ var Act = class {
5334
5240
  if (!this._drain) return { subscribed: 0, last_id: -1, scanned: false };
5335
5241
  return this._scoped(async () => {
5336
5242
  const { subscribed, last_id, marked, scanned } = await this._correlate.correlate(query, lease);
5337
- if ((subscribed > 0 || marked > 0) && this._reactive_events.size > 0)
5338
- this._arm_all();
5243
+ if (subscribed > 0 || marked > 0) this._arm_all();
5339
5244
  if (subscribed > 0) this._on_discovered?.(subscribed);
5340
5245
  return { subscribed, last_id, scanned };
5341
5246
  });
@@ -5427,12 +5332,6 @@ var Act = class {
5427
5332
  * app.settle({ eventLimit: 1000 }); // emits "settled" when fully replayed
5428
5333
  * ```
5429
5334
  *
5430
- * @example Rebuild a projection (tests / scripts)
5431
- * ```typescript
5432
- * await app.reset(["my-projection"]);
5433
- * await app.drain({ eventLimit: 1000 }); // small streams: one pass is enough
5434
- * ```
5435
- *
5436
5335
  * @see {@link Store.reset} for the underlying store primitive
5437
5336
  * @see {@link settle} for the debounced full-catch-up loop
5438
5337
  */
@@ -5441,7 +5340,7 @@ var Act = class {
5441
5340
  const count = await store2().reset(input);
5442
5341
  for (const handler of this._batch_handlers.values())
5443
5342
  handler[FOLD_RESET]?.();
5444
- if (count > 0 && this._reactive_events.size > 0) this._arm_all();
5343
+ if (count > 0) this._arm_all();
5445
5344
  return count;
5446
5345
  });
5447
5346
  }
@@ -5475,7 +5374,7 @@ var Act = class {
5475
5374
  async unblock(input) {
5476
5375
  return this._scoped(async () => {
5477
5376
  const count = await store2().unblock(input);
5478
- if (count > 0 && this._reactive_events.size > 0) this._arm_all();
5377
+ if (count > 0) this._arm_all();
5479
5378
  return count;
5480
5379
  });
5481
5380
  }
@@ -5511,11 +5410,6 @@ var Act = class {
5511
5410
  * await cache().clear(); // operator's responsibility
5512
5411
  * ```
5513
5412
  *
5514
- * @example Copy one store into another
5515
- * ```typescript
5516
- * await app.restore(pg, {}, sqlite);
5517
- * ```
5518
- *
5519
5413
  * @see {@link Store.restore} for the underlying driver-pattern primitive.
5520
5414
  */
5521
5415
  async restore(source, opts = {}, sink) {
@@ -5654,16 +5548,6 @@ var Act = class {
5654
5548
  * await app.prioritize({ stream: "^proj-orders$", stream_exact: false }, 10);
5655
5549
  * ```
5656
5550
  *
5657
- * @example Drop all audit projections to background
5658
- * ```typescript
5659
- * await app.prioritize({ source: "^audit-" }, -5);
5660
- * ```
5661
- *
5662
- * @example Reset everyone to default
5663
- * ```typescript
5664
- * await app.prioritize({}, 0);
5665
- * ```
5666
- *
5667
5551
  * @see {@link Store.prioritize} for the underlying primitive
5668
5552
  * @see {@link claim} for how priority biases scheduling
5669
5553
  */
@@ -5674,7 +5558,7 @@ var Act = class {
5674
5558
  async _run_close(targets) {
5675
5559
  const close_actor = { id: "$close", name: "close" };
5676
5560
  const result = await run_close_cycle(targets, {
5677
- reactive_events_size: this._reactive_events.size,
5561
+ reactive: this._reactive,
5678
5562
  catch_up_correlation: (until) => catch_up_correlation(
5679
5563
  this._correlate,
5680
5564
  (limit) => this.correlate({ limit }),
@@ -5727,27 +5611,6 @@ var Act = class {
5727
5611
  * { stream: "order-456" },
5728
5612
  * ]);
5729
5613
  * ```
5730
- *
5731
- * @example Close with restart (state loaded automatically after guard)
5732
- * ```typescript
5733
- * await app.close([
5734
- * { stream: "counter-1", restart: true },
5735
- * { stream: "counter-2" }, // tombstoned
5736
- * ]);
5737
- * ```
5738
- *
5739
- * @example Windowed close — keep the last 180 days of real events
5740
- * ```typescript
5741
- * const cutoff = new Date();
5742
- * cutoff.setDate(cutoff.getDate() - 180);
5743
- * await app.close([
5744
- * {
5745
- * stream: "ledger-acme",
5746
- * before: cutoff,
5747
- * archive: async () => { await archiveToS3("ledger-acme", cutoff); },
5748
- * },
5749
- * ]);
5750
- * ```
5751
5614
  */
5752
5615
  async close(targets) {
5753
5616
  if (!targets.length) return { truncated: /* @__PURE__ */ new Map(), skipped: [] };