@rotorsoft/act 0.35.1 → 0.35.2

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 (82) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/@types/act.d.ts +672 -0
  3. package/dist/@types/act.d.ts.map +1 -0
  4. package/dist/@types/adapters/console-logger.d.ts +41 -0
  5. package/dist/@types/adapters/console-logger.d.ts.map +1 -0
  6. package/dist/@types/adapters/in-memory-cache.d.ts +34 -0
  7. package/dist/@types/adapters/in-memory-cache.d.ts.map +1 -0
  8. package/dist/@types/adapters/in-memory-store.d.ts +202 -0
  9. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -0
  10. package/dist/@types/adapters/index.d.ts +4 -0
  11. package/dist/@types/adapters/index.d.ts.map +1 -0
  12. package/dist/@types/builders/act-builder.d.ts +160 -0
  13. package/dist/@types/builders/act-builder.d.ts.map +1 -0
  14. package/dist/@types/builders/index.d.ts +13 -0
  15. package/dist/@types/builders/index.d.ts.map +1 -0
  16. package/dist/@types/builders/projection-builder.d.ts +101 -0
  17. package/dist/@types/builders/projection-builder.d.ts.map +1 -0
  18. package/dist/@types/builders/slice-builder.d.ts +109 -0
  19. package/dist/@types/builders/slice-builder.d.ts.map +1 -0
  20. package/dist/@types/builders/state-builder.d.ts +424 -0
  21. package/dist/@types/builders/state-builder.d.ts.map +1 -0
  22. package/dist/@types/config.d.ts +119 -0
  23. package/dist/@types/config.d.ts.map +1 -0
  24. package/dist/@types/index.d.ts +14 -0
  25. package/dist/@types/index.d.ts.map +1 -0
  26. package/dist/@types/internal/build-classify.d.ts +44 -0
  27. package/dist/@types/internal/build-classify.d.ts.map +1 -0
  28. package/dist/@types/internal/close-cycle.d.ts +38 -0
  29. package/dist/@types/internal/close-cycle.d.ts.map +1 -0
  30. package/dist/@types/internal/correlate-cycle.d.ts +78 -0
  31. package/dist/@types/internal/correlate-cycle.d.ts.map +1 -0
  32. package/dist/@types/internal/drain-cycle.d.ts +113 -0
  33. package/dist/@types/internal/drain-cycle.d.ts.map +1 -0
  34. package/dist/@types/internal/drain-ratio.d.ts +26 -0
  35. package/dist/@types/internal/drain-ratio.d.ts.map +1 -0
  36. package/dist/@types/internal/drain.d.ts +41 -0
  37. package/dist/@types/internal/drain.d.ts.map +1 -0
  38. package/dist/@types/internal/event-sourcing.d.ts +96 -0
  39. package/dist/@types/internal/event-sourcing.d.ts.map +1 -0
  40. package/dist/@types/internal/index.d.ts +29 -0
  41. package/dist/@types/internal/index.d.ts.map +1 -0
  42. package/dist/@types/internal/merge.d.ts +31 -0
  43. package/dist/@types/internal/merge.d.ts.map +1 -0
  44. package/dist/@types/internal/reactions.d.ts +54 -0
  45. package/dist/@types/internal/reactions.d.ts.map +1 -0
  46. package/dist/@types/internal/settle.d.ts +60 -0
  47. package/dist/@types/internal/settle.d.ts.map +1 -0
  48. package/dist/@types/internal/tracing.d.ts +45 -0
  49. package/dist/@types/internal/tracing.d.ts.map +1 -0
  50. package/dist/@types/lru-map.d.ts +50 -0
  51. package/dist/@types/lru-map.d.ts.map +1 -0
  52. package/dist/@types/ports.d.ts +196 -0
  53. package/dist/@types/ports.d.ts.map +1 -0
  54. package/dist/@types/signals.d.ts +2 -0
  55. package/dist/@types/signals.d.ts.map +1 -0
  56. package/dist/@types/types/action.d.ts +444 -0
  57. package/dist/@types/types/action.d.ts.map +1 -0
  58. package/dist/@types/types/errors.d.ts +284 -0
  59. package/dist/@types/types/errors.d.ts.map +1 -0
  60. package/dist/@types/types/index.d.ts +39 -0
  61. package/dist/@types/types/index.d.ts.map +1 -0
  62. package/dist/@types/types/ports.d.ts +617 -0
  63. package/dist/@types/types/ports.d.ts.map +1 -0
  64. package/dist/@types/types/reaction.d.ts +314 -0
  65. package/dist/@types/types/reaction.d.ts.map +1 -0
  66. package/dist/@types/types/registry.d.ts +74 -0
  67. package/dist/@types/types/registry.d.ts.map +1 -0
  68. package/dist/@types/types/schemas.d.ts +117 -0
  69. package/dist/@types/types/schemas.d.ts.map +1 -0
  70. package/dist/@types/utils.d.ts +54 -0
  71. package/dist/@types/utils.d.ts.map +1 -0
  72. package/dist/chunk-AGWZY6YT.js +127 -0
  73. package/dist/chunk-AGWZY6YT.js.map +1 -0
  74. package/dist/index.cjs +3144 -0
  75. package/dist/index.cjs.map +1 -0
  76. package/dist/index.js +2975 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/types/index.cjs +166 -0
  79. package/dist/types/index.cjs.map +1 -0
  80. package/dist/types/index.js +33 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/package.json +6 -2
@@ -0,0 +1,672 @@
1
+ import type { Actor, AsOf, BatchHandler, BlockedLease, CloseResult, CloseTarget, Committed, Drain, DrainOptions, IAct, Lease, PrioritizeFilter, Query, Registry, Schema, SchemaRegister, Schemas, SettleOptions, Snapshot, State, StoreNotification, Target } from "./types/index.js";
2
+ /**
3
+ * @category Orchestrator
4
+ * @see Store
5
+ *
6
+ * Main orchestrator for event-sourced state machines and workflows.
7
+ *
8
+ * It manages the lifecycle of actions, reactions, and event streams, providing APIs for loading state, executing actions, querying events, and draining reactions.
9
+ *
10
+ * ## Usage
11
+ *
12
+ * ```typescript
13
+ * const app = new Act(registry, 100);
14
+ * await app.do("increment", { stream: "counter1", actor }, { by: 1 });
15
+ * const snapshot = await app.load(Counter, "counter1");
16
+ * await app.drain();
17
+ * ```
18
+ *
19
+ * - Register event listeners with `.on("committed", ...)` and `.on("acked", ...)` to react to lifecycle events.
20
+ * - Use `.query()` to analyze event streams for analytics or debugging.
21
+ *
22
+ * @template TSchemaReg SchemaRegister for state
23
+ * @template TEvents Schemas for events
24
+ * @template TActions Schemas for actions
25
+ * @template TStateMap Map of state names to state schemas
26
+ * @template TActor Actor type extending base Actor
27
+ */
28
+ /**
29
+ * Default LRU cap for the subscribed-streams cache. Apps that mint many
30
+ * dynamic targets (one per aggregate) should override via
31
+ * {@link ActOptions.maxSubscribedStreams} based on expected concurrency.
32
+ */
33
+ export declare const DEFAULT_MAX_SUBSCRIBED_STREAMS = 1000;
34
+ /**
35
+ * Default debounce window (ms) for `settle()` when neither the per-call
36
+ * `SettleOptions.debounceMs` nor `ActOptions.settleDebounceMs` is set.
37
+ * Coalesces commits in the same tick and small bursts; sub-perceptible
38
+ * latency on the `"settled"` signal.
39
+ */
40
+ export declare const DEFAULT_SETTLE_DEBOUNCE_MS = 10;
41
+ /**
42
+ * Lifecycle events emitted by {@link Act}, mapped to their payload type.
43
+ * Drives the typing of `emit` / `on` / `off` — the event-name argument
44
+ * narrows its payload at the call site.
45
+ */
46
+ export type ActLifecycleEvents<TSchemaReg extends SchemaRegister<TActions>, TEvents extends Schemas, TActions extends Schemas> = {
47
+ committed: Snapshot<TSchemaReg, TEvents>[];
48
+ acked: Lease[];
49
+ blocked: BlockedLease[];
50
+ settled: Drain<TEvents>;
51
+ closed: CloseResult;
52
+ /**
53
+ * A **different process** committed an event to the same backing store.
54
+ *
55
+ * Fires only when the configured store implements
56
+ * {@link Store.notify} and there is at least one registered reaction.
57
+ * The orchestrator uses the same signal internally to wake `settle()`
58
+ * — listeners get the raw payload for SSE fan-out, dashboards, and
59
+ * audit logs.
60
+ *
61
+ * Local commits do *not* fire `notified` (use `committed` for those):
62
+ * stores self-filter their own writes so this channel has a clean
63
+ * cross-process semantic.
64
+ */
65
+ notified: StoreNotification;
66
+ };
67
+ /**
68
+ * Options for {@link Act} construction (passed via {@link ActBuilder.build}).
69
+ *
70
+ * @property maxSubscribedStreams - Cap for the LRU set tracking already-
71
+ * subscribed reaction streams. Default: {@link DEFAULT_MAX_SUBSCRIBED_STREAMS}.
72
+ * @property settleDebounceMs - Debounce window (ms) used by `settle()` when
73
+ * the caller doesn't pass `SettleOptions.debounceMs`. Tune this once per
74
+ * Act instance instead of threading the value through every call site.
75
+ * Default: {@link DEFAULT_SETTLE_DEBOUNCE_MS}.
76
+ */
77
+ export type ActOptions = {
78
+ readonly maxSubscribedStreams?: number;
79
+ readonly settleDebounceMs?: number;
80
+ };
81
+ export declare class Act<TSchemaReg extends SchemaRegister<TActions>, TEvents extends Schemas, TActions extends Schemas, TStateMap extends Record<string, Schema> = Record<string, never>, TActor extends Actor = Actor> implements IAct<TEvents, TActions, TActor> {
82
+ readonly registry: Registry<TSchemaReg, TEvents, TActions>;
83
+ private readonly _states;
84
+ private _emitter;
85
+ /** Event names with at least one registered reaction (computed at build time) */
86
+ private readonly _reactive_events;
87
+ /** Drain pipeline driver: armed flag, concurrency lock, adaptive ratio. */
88
+ private readonly _drain;
89
+ /** Correlation state machine: lazy init, dynamic-resolver scan, periodic worker. */
90
+ private readonly _correlate;
91
+ /** Debounced correlate→drain catch-up loop. */
92
+ private readonly _settle;
93
+ /**
94
+ * Disposer for the cross-process notify subscription, set up eagerly
95
+ * during construction. Held as a promise because the subscription
96
+ * itself may be async (the PG adapter checks out a dedicated client
97
+ * and runs `LISTEN` before resolving). Resolves to `undefined` when
98
+ * the store doesn't implement `notify` or there are no registered
99
+ * reactions.
100
+ *
101
+ * **Contract:** the configured store must be injected via
102
+ * {@link store}`(adapter)` *before* calling `act()...build()`. The
103
+ * orchestrator wires notify against whatever store is current at
104
+ * construction time — late injection after build is unsupported.
105
+ */
106
+ private readonly _notify_disposer;
107
+ /**
108
+ * Emit a lifecycle event. The payload type is inferred from the event name
109
+ * via {@link ActLifecycleEvents}.
110
+ */
111
+ emit<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(event: E, args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]): boolean;
112
+ /**
113
+ * Register a listener for a lifecycle event. The listener receives the
114
+ * event-specific payload.
115
+ */
116
+ on<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(event: E, listener: (args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]) => void): this;
117
+ /**
118
+ * Remove a previously registered lifecycle listener.
119
+ */
120
+ off<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(event: E, listener: (args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]) => void): this;
121
+ /** Batch handlers for static-target projections (target → handler) */
122
+ private readonly _batch_handlers;
123
+ /** Event-sourcing handlers, optionally wrapped with trace decorators */
124
+ private readonly _es;
125
+ /** Correlate/drain pipeline ops, optionally wrapped with trace decorators */
126
+ private readonly _cd;
127
+ /**
128
+ * Event-name → owning state, computed at build time. The duplicate-event
129
+ * guard in merge.ts ensures one event name maps to at most one state, so
130
+ * this lookup is unambiguous. Used by `close()` to pick the right reducer
131
+ * set when seeding a `restart` snapshot in multi-state apps.
132
+ */
133
+ private readonly _event_to_state;
134
+ /** Logger resolved at construction time (after user port configuration) */
135
+ private readonly _logger;
136
+ /** Pre-bound IAct methods reused across drain cycles. Only `do` varies per
137
+ * payload (it captures the triggering event for reactingTo auto-inject). */
138
+ private readonly _bound_do;
139
+ private readonly _bound_load;
140
+ private readonly _bound_query;
141
+ private readonly _bound_query_array;
142
+ /** Reaction dispatchers built once and handed to runDrainCycle each cycle. */
143
+ private readonly _handle;
144
+ private readonly _handle_batch;
145
+ /**
146
+ * Create a new Act orchestrator. Prefer the {@link act} builder over
147
+ * direct construction — `act()...build()` wires the registry, merges
148
+ * partial states, and collects batch handlers from registered slices
149
+ * and projections in one pass.
150
+ *
151
+ * @param registry Schemas for every event and action across registered states
152
+ * @param _states Merged map of state name → state definition
153
+ * @param batchHandlers Static-target projection batch handlers (target → handler)
154
+ * @param options Tuning knobs — see {@link ActOptions}
155
+ */
156
+ constructor(registry: Registry<TSchemaReg, TEvents, TActions>, _states?: Map<string, State<any, any, any>>, batchHandlers?: Map<string, BatchHandler<any>>, options?: ActOptions);
157
+ /**
158
+ * Subscribe to {@link Store.notify} when both the store and the
159
+ * registry support it. Returns the disposer (or `undefined` when no
160
+ * subscription was made). Errors during subscription are logged but
161
+ * never thrown — `notify` is a hint, not a contract.
162
+ */
163
+ private _wireNotify;
164
+ /**
165
+ * Executes an action on a state instance, committing resulting events.
166
+ *
167
+ * This is the primary method for modifying state. It:
168
+ * 1. Validates the action payload against the schema
169
+ * 2. Loads the current state snapshot
170
+ * 3. Checks invariants (business rules)
171
+ * 4. Executes the action handler to generate events
172
+ * 5. Applies events to create new state
173
+ * 6. Commits events to the store with optimistic concurrency control
174
+ *
175
+ * @template TKey - Action name from registered actions
176
+ * @param action - The name of the action to execute
177
+ * @param target - Target specification with stream ID and actor context
178
+ * @param payload - Action payload matching the action's schema
179
+ * @param reactingTo - Optional event that triggered this action (for correlation)
180
+ * @param skipValidation - Skip schema validation (use carefully, for performance)
181
+ * @returns Array of snapshots for all affected states (usually one)
182
+ *
183
+ * @throws {ValidationError} If payload doesn't match action schema
184
+ * @throws {InvariantError} If business rules are violated
185
+ * @throws {ConcurrencyError} If another process modified the stream
186
+ *
187
+ * @example Basic action execution
188
+ * ```typescript
189
+ * const snapshots = await app.do(
190
+ * "increment",
191
+ * {
192
+ * stream: "counter-1",
193
+ * actor: { id: "user1", name: "Alice" }
194
+ * },
195
+ * { by: 5 }
196
+ * );
197
+ *
198
+ * console.log(snapshots[0].state.count); // Current count after increment
199
+ * ```
200
+ *
201
+ * @example With error handling
202
+ * ```typescript
203
+ * try {
204
+ * await app.do(
205
+ * "withdraw",
206
+ * { stream: "account-123", actor: { id: "user1", name: "Alice" } },
207
+ * { amount: 1000 }
208
+ * );
209
+ * } catch (error) {
210
+ * if (error instanceof InvariantError) {
211
+ * console.error("Business rule violated:", error.description);
212
+ * } else if (error instanceof ConcurrencyError) {
213
+ * console.error("Concurrent modification detected, retry...");
214
+ * } else if (error instanceof ValidationError) {
215
+ * console.error("Invalid payload:", error.details);
216
+ * }
217
+ * }
218
+ * ```
219
+ *
220
+ * @example Reaction triggering another action (reactingTo auto-injected)
221
+ * ```typescript
222
+ * const app = act()
223
+ * .withState(Order)
224
+ * .withState(Inventory)
225
+ * .on("OrderPlaced")
226
+ * .do(async function reduceInventory(event, _stream, app) {
227
+ * // Inside reaction handlers, reactingTo is auto-injected when omitted.
228
+ * // The triggering event is used by default, maintaining the correlation chain.
229
+ * await app.do(
230
+ * "reduceStock",
231
+ * { stream: "inventory-1", actor: { id: "sys", name: "system" } },
232
+ * { amount: event.data.items.length }
233
+ * );
234
+ * // To use a different correlation, pass reactingTo explicitly:
235
+ * // await app.do("reduceStock", target, payload, customEvent);
236
+ * })
237
+ * .to("inventory-1")
238
+ * .build();
239
+ * ```
240
+ *
241
+ * @see {@link Target} for target structure
242
+ * @see {@link Snapshot} for return value structure
243
+ * @see {@link ValidationError}, {@link InvariantError}, {@link ConcurrencyError}
244
+ */
245
+ do<TKey extends keyof TActions>(action: TKey, target: Target<TActor>, payload: Readonly<TActions[TKey]>, reactingTo?: Committed<TEvents, string & keyof TEvents>, skipValidation?: boolean): Promise<Snapshot<TSchemaReg[TKey], TEvents>[]>;
246
+ /**
247
+ * Loads the current state snapshot for a specific stream.
248
+ *
249
+ * Reconstructs the current state by replaying events from the event store.
250
+ * Uses snapshots when available to optimize loading performance.
251
+ *
252
+ * Accepts either a State definition object or a state name string. When
253
+ * using a string, the merged state (from partial states registered via
254
+ * `.withState()`) is resolved by name.
255
+ *
256
+ * @template TNewState - State schema type
257
+ * @template TNewEvents - Event schemas type
258
+ * @template TNewActions - Action schemas type
259
+ * @param state - The state definition or state name to load
260
+ * @param stream - The stream ID (state instance identifier)
261
+ * @param callback - Optional callback invoked with the loaded snapshot
262
+ * @returns The current state snapshot for the stream
263
+ *
264
+ * @example Load by state definition
265
+ * ```typescript
266
+ * const snapshot = await app.load(Counter, "counter-1");
267
+ * console.log(snapshot.state.count); // Current count
268
+ * console.log(snapshot.patches); // Events since last snapshot
269
+ * ```
270
+ *
271
+ * @example Load by state name (useful with partial states)
272
+ * ```typescript
273
+ * const snapshot = await app.load("Ticket", "ticket-123");
274
+ * console.log(snapshot.state.title); // Merged state from all partials
275
+ * ```
276
+ *
277
+ * @example Load multiple states
278
+ * ```typescript
279
+ * const [user, account] = await Promise.all([
280
+ * app.load(User, "user-123"),
281
+ * app.load(BankAccount, "account-456")
282
+ * ]);
283
+ * ```
284
+ *
285
+ * @see {@link Snapshot} for snapshot structure
286
+ */
287
+ load<TNewState extends Schema, TNewEvents extends Schemas, TNewActions extends Schemas>(state: State<TNewState, TNewEvents, TNewActions>, stream: string, callback?: (snapshot: Snapshot<TNewState, TNewEvents>) => void, asOf?: AsOf): Promise<Snapshot<TNewState, TNewEvents>>;
288
+ load<TKey extends keyof TStateMap & string>(name: TKey, stream: string, callback?: (snapshot: Snapshot<TStateMap[TKey], TEvents>) => void, asOf?: AsOf): Promise<Snapshot<TStateMap[TKey], TEvents>>;
289
+ /**
290
+ * Queries the event store for events matching a filter.
291
+ *
292
+ * Use this for analyzing event streams, generating reports, or debugging.
293
+ * The callback is invoked for each matching event, and the method returns
294
+ * summary information (first event, last event, total count).
295
+ *
296
+ * For small result sets, consider using {@link query_array} instead.
297
+ *
298
+ * @param query - Filter criteria — see {@link Query} for available fields
299
+ * (`stream`, `name`, `after`, `before`, `created_after`, `created_before`,
300
+ * `limit`, `with_snaps`, `stream_exact`)
301
+ * @param callback - Optional callback invoked for each matching event
302
+ * @returns Object with first event, last event, and total count
303
+ *
304
+ * @example Query all events for a stream
305
+ * ```typescript
306
+ * const { first, last, count } = await app.query(
307
+ * { stream: "counter-1" },
308
+ * (event) => console.log(event.name, event.data)
309
+ * );
310
+ * console.log(`Found ${count} events from ${first?.id} to ${last?.id}`);
311
+ * ```
312
+ *
313
+ * @example Query specific event types
314
+ * ```typescript
315
+ * const { count } = await app.query(
316
+ * { name: "UserCreated", limit: 100 },
317
+ * (event) => {
318
+ * console.log("User created:", event.data.email);
319
+ * }
320
+ * );
321
+ * ```
322
+ *
323
+ * @example Query events in time range
324
+ * ```typescript
325
+ * const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
326
+ * const { count } = await app.query({
327
+ * created_after: yesterday,
328
+ * stream: "user-123"
329
+ * });
330
+ * console.log(`User had ${count} events in last 24 hours`);
331
+ * ```
332
+ *
333
+ * @see {@link query_array} for loading events into memory
334
+ */
335
+ query(query: Query, callback?: (event: Committed<TEvents, keyof TEvents>) => void): Promise<{
336
+ first?: Committed<TEvents, keyof TEvents>;
337
+ last?: Committed<TEvents, keyof TEvents>;
338
+ count: number;
339
+ }>;
340
+ /**
341
+ * Queries the event store and returns all matching events in memory.
342
+ *
343
+ * **Use with caution** - this loads all results into memory. For large result sets,
344
+ * use {@link query} with a callback instead to process events incrementally.
345
+ *
346
+ * @param query - The query filter (same as {@link query})
347
+ * @returns Array of all matching events
348
+ *
349
+ * @example Load all events for a stream
350
+ * ```typescript
351
+ * const events = await app.query_array({ stream: "counter-1" });
352
+ * console.log(`Loaded ${events.length} events`);
353
+ * events.forEach(event => console.log(event.name, event.data));
354
+ * ```
355
+ *
356
+ * @example Get recent events
357
+ * ```typescript
358
+ * const recent = await app.query_array({
359
+ * stream: "user-123",
360
+ * limit: 10
361
+ * });
362
+ * ```
363
+ *
364
+ * @see {@link query} for large result sets
365
+ */
366
+ query_array(query: Query): Promise<Committed<TEvents, keyof TEvents>[]>;
367
+ /**
368
+ * Processes pending reactions by draining uncommitted events from the event store.
369
+ *
370
+ * Runs a single drain cycle:
371
+ * 1. Polls the store for streams with uncommitted events
372
+ * 2. Leases streams to prevent concurrent processing
373
+ * 3. Fetches events for each leased stream
374
+ * 4. Executes matching reaction handlers
375
+ * 5. Acknowledges successful reactions or blocks failing ones
376
+ *
377
+ * Drain uses a dual-frontier strategy to balance processing of new streams (lagging)
378
+ * vs active streams (leading). The ratio adapts based on event pressure.
379
+ *
380
+ * Call `correlate()` before `drain()` to discover target streams. For a higher-level
381
+ * API that handles debouncing, correlation, and signaling automatically, use {@link settle}.
382
+ *
383
+ * @param options - Drain configuration — see {@link DrainOptions} for fields
384
+ * (`streamLimit`, `eventLimit`, `leaseMillis`).
385
+ * @returns Drain statistics with fetched, leased, acked, and blocked counts
386
+ *
387
+ * @example In tests and scripts
388
+ * ```typescript
389
+ * await app.do("createUser", target, payload);
390
+ * await app.correlate();
391
+ * await app.drain();
392
+ * ```
393
+ *
394
+ * @example In production, prefer settle()
395
+ * ```typescript
396
+ * await app.do("CreateItem", target, input);
397
+ * app.settle(); // debounced correlate→drain, emits "settled"
398
+ * ```
399
+ *
400
+ * @see {@link settle} for debounced correlate→drain with lifecycle events
401
+ * @see {@link correlate} for dynamic stream discovery
402
+ * @see {@link start_correlations} for automatic correlation
403
+ */
404
+ drain(options?: DrainOptions): Promise<Drain<TEvents>>;
405
+ /**
406
+ * Discovers and registers new streams dynamically based on reaction resolvers.
407
+ *
408
+ * Correlation enables "dynamic reactions" where target streams are determined at runtime
409
+ * based on event content. For example, you might create a stats stream for each user
410
+ * when they perform certain actions.
411
+ *
412
+ * This method scans events matching the query and identifies new target streams based
413
+ * on reaction resolvers. It then registers these streams so they'll be picked up by
414
+ * the next drain cycle.
415
+ *
416
+ * @param query - Query filter to scan for new correlations
417
+ * @param query - Scan filter — see {@link Query} for fields (typically
418
+ * `{ after: <event-id>, limit: <count> }`)
419
+ * @returns Object with newly leased streams and last scanned event ID
420
+ *
421
+ * @example Manual correlation
422
+ * ```typescript
423
+ * // Scan for new streams
424
+ * const { leased, last_id } = await app.correlate({ after: 0, limit: 100 });
425
+ * console.log(`Found ${leased.length} new streams`);
426
+ *
427
+ * // Save last_id for next scan
428
+ * await saveCheckpoint(last_id);
429
+ * ```
430
+ *
431
+ * @example Dynamic stream creation
432
+ * ```typescript
433
+ * const app = act()
434
+ * .withState(User)
435
+ * .withState(UserStats)
436
+ * .on("UserLoggedIn")
437
+ * .do(async (event) => ["incrementLoginCount", {}])
438
+ * .to((event) => ({
439
+ * target: `stats-${event.stream}` // Dynamic target per user
440
+ * }))
441
+ * .build();
442
+ *
443
+ * // Discover stats streams as users log in
444
+ * await app.correlate();
445
+ * ```
446
+ *
447
+ * @see {@link start_correlations} for automatic periodic correlation
448
+ * @see {@link stop_correlations} to stop automatic correlation
449
+ */
450
+ correlate(query?: Query): Promise<{
451
+ subscribed: number;
452
+ last_id: number;
453
+ }>;
454
+ /**
455
+ * Starts automatic periodic correlation worker for discovering new streams.
456
+ *
457
+ * The correlation worker runs in the background, scanning for new events and identifying
458
+ * new target streams based on reaction resolvers. It maintains a sliding window that
459
+ * advances with each scan, ensuring all events are eventually correlated.
460
+ *
461
+ * This is useful for dynamic stream creation patterns where you don't know all streams
462
+ * upfront - they're discovered as events arrive.
463
+ *
464
+ * **Note:** Only one correlation worker can run at a time per Act instance.
465
+ *
466
+ * @param query - Query filter for correlation scans — see {@link Query}
467
+ * (typically `{ after: -1, limit: 100 }`)
468
+ * @param frequency - Correlation frequency in milliseconds (default: 10000)
469
+ * @param callback - Optional callback invoked with newly discovered streams
470
+ * @returns `true` if worker started, `false` if already running
471
+ *
472
+ * @example Start automatic correlation
473
+ * ```typescript
474
+ * // Start correlation worker scanning every 5 seconds
475
+ * app.start_correlations(
476
+ * { after: 0, limit: 100 },
477
+ * 5000,
478
+ * (leased) => {
479
+ * console.log(`Discovered ${leased.length} new streams`);
480
+ * }
481
+ * );
482
+ *
483
+ * // Later, stop it
484
+ * app.stop_correlations();
485
+ * ```
486
+ *
487
+ * @example With checkpoint persistence
488
+ * ```typescript
489
+ * // Load last checkpoint
490
+ * const lastId = await loadCheckpoint();
491
+ *
492
+ * app.start_correlations(
493
+ * { after: lastId, limit: 100 },
494
+ * 10000,
495
+ * async (leased) => {
496
+ * // Save checkpoint for next restart
497
+ * if (leased.length) {
498
+ * const maxId = Math.max(...leased.map(l => l.at));
499
+ * await saveCheckpoint(maxId);
500
+ * }
501
+ * }
502
+ * );
503
+ * ```
504
+ *
505
+ * @see {@link correlate} for manual one-time correlation
506
+ * @see {@link stop_correlations} to stop the worker
507
+ */
508
+ start_correlations(query?: Query, frequency?: number, callback?: (subscribed: number) => void): boolean;
509
+ /**
510
+ * Stops the automatic correlation worker.
511
+ *
512
+ * Call this to stop the background correlation worker started by {@link start_correlations}.
513
+ * This is automatically called when the Act instance is disposed.
514
+ *
515
+ * @example
516
+ * ```typescript
517
+ * // Start correlation
518
+ * app.start_correlations();
519
+ *
520
+ * // Later, stop it
521
+ * app.stop_correlations();
522
+ * ```
523
+ *
524
+ * @see {@link start_correlations}
525
+ */
526
+ stop_correlations(): void;
527
+ /**
528
+ * Cancels any pending or active settle cycle.
529
+ *
530
+ * @see {@link settle}
531
+ */
532
+ stop_settling(): void;
533
+ /**
534
+ * Reset reaction stream watermarks and request a drain on the next
535
+ * `drain()` / `settle()` cycle.
536
+ *
537
+ * Use this to replay events through projections (or other reaction targets)
538
+ * after changing handler logic. Equivalent to calling `store().reset(streams)`
539
+ * directly, but also raises the orchestrator's internal "needs drain" flag —
540
+ * `store().reset(...)` alone leaves the flag untouched, so a settled app
541
+ * would short-circuit and skip the replay.
542
+ *
543
+ * Pair with `app.settle()` (or a single `app.drain()` for small streams).
544
+ * `settle()` loops correlate→drain until no progress is made, so one call
545
+ * fully catches up paginated streams without forcing callers to roll
546
+ * their own loop.
547
+ *
548
+ * @param streams - Reaction target streams (e.g., projection names) to reset
549
+ * @returns Count of streams that were actually reset
550
+ *
551
+ * @example Rebuild a projection (production)
552
+ * ```typescript
553
+ * await app.reset(["my-projection"]);
554
+ * app.settle({ eventLimit: 1000 }); // emits "settled" when fully replayed
555
+ * ```
556
+ *
557
+ * @example Rebuild a projection (tests / scripts)
558
+ * ```typescript
559
+ * await app.reset(["my-projection"]);
560
+ * await app.drain({ eventLimit: 1000 }); // small streams: one pass is enough
561
+ * ```
562
+ *
563
+ * @see {@link Store.reset} for the underlying store primitive
564
+ * @see {@link settle} for the debounced full-catch-up loop
565
+ */
566
+ reset(streams: string[]): Promise<number>;
567
+ /**
568
+ * Bulk-update scheduling priority for streams matching `filter`.
569
+ *
570
+ * Operator-grade override of the `claim()` lagging-frontier
571
+ * ordering (ACT-102). Useful when a long-running replay needs to
572
+ * jump ahead of other lagging streams, or when a no-longer-urgent
573
+ * job should yield slots back to the rest. Build-time priorities
574
+ * (set via the resolver's `priority` field) are subject to a
575
+ * `max()` invariant across reactions; this API ignores that and
576
+ * sets the priority outright on every matching row.
577
+ *
578
+ * Filter shape mirrors {@link query} / {@link Store.query_streams}:
579
+ * `stream` / `source` are regex by default, exact with the
580
+ * `*_exact` flags; `blocked` restricts to blocked or unblocked
581
+ * rows. **An empty filter (`{}`) updates every registered stream.**
582
+ *
583
+ * @param filter - Selection criteria (regex by default).
584
+ * @param priority - New priority value. Set as-is — no clamp.
585
+ * @returns Count of streams whose priority changed.
586
+ *
587
+ * @example Boost a specific projection mid-replay
588
+ * ```typescript
589
+ * await app.prioritize({ stream: "^proj-orders$", stream_exact: false }, 10);
590
+ * ```
591
+ *
592
+ * @example Drop all audit projections to background
593
+ * ```typescript
594
+ * await app.prioritize({ source: "^audit-" }, -5);
595
+ * ```
596
+ *
597
+ * @example Reset everyone to default
598
+ * ```typescript
599
+ * await app.prioritize({}, 0);
600
+ * ```
601
+ *
602
+ * @see {@link Store.prioritize} for the underlying primitive
603
+ * @see {@link claim} for how priority biases scheduling
604
+ */
605
+ prioritize(filter: PrioritizeFilter, priority: number): Promise<number>;
606
+ /**
607
+ * Close the books — guard, archive, truncate, and optionally restart streams.
608
+ *
609
+ * Safely removes historical events from the operational store:
610
+ *
611
+ * 1. **Correlate** — discover pending reaction targets
612
+ * 2. **Safety check** — skip streams with pending reactions (skipped when no reactive events)
613
+ * 3. **Guard** — commit `__tombstone__` with `expectedVersion` to block concurrent writes
614
+ * 4. **Load state** — for streams in `snapshots`, load final state while guarded (no races)
615
+ * 5. **Archive** — user callback per stream (abort-all on failure, streams are guarded)
616
+ * 6. **Truncate + seed** — atomic: delete all events, insert `__snapshot__` or `__tombstone__`
617
+ * 7. **Cache** — invalidate (tombstoned) or warm (restarted)
618
+ * 8. **Emit "closed"** — lifecycle event with results
619
+ *
620
+ * @param targets - Per-stream close options (stream, restart?, archive?)
621
+ * @returns `{ truncated: TruncateResult, skipped: string[] }`
622
+ *
623
+ * @example Archive and close
624
+ * ```typescript
625
+ * await app.close([
626
+ * { stream: "order-123", archive: async () => { await archiveToS3("order-123"); } },
627
+ * { stream: "order-456" },
628
+ * ]);
629
+ * ```
630
+ *
631
+ * @example Close with restart (state loaded automatically after guard)
632
+ * ```typescript
633
+ * await app.close([
634
+ * { stream: "counter-1", restart: true },
635
+ * { stream: "counter-2" }, // tombstoned
636
+ * ]);
637
+ * ```
638
+ */
639
+ close(targets: CloseTarget[]): Promise<CloseResult>;
640
+ /**
641
+ * Debounced, non-blocking correlate→drain cycle.
642
+ *
643
+ * Call this after `app.do()` (or `app.reset()`) to schedule a background
644
+ * drain. Multiple rapid calls within the debounce window are coalesced
645
+ * into a single cycle. Runs correlate→drain in a loop until a pass makes
646
+ * no progress — no new subscriptions, no acks, no blocks — then emits
647
+ * the `"settled"` lifecycle event. This means a single `settle()` call
648
+ * fully catches up paginated streams (e.g. after `reset()` on a long
649
+ * projection) without forcing callers to loop.
650
+ *
651
+ * @param options - Settle configuration — see {@link SettleOptions} for fields:
652
+ * `debounceMs` (default 10), `correlate` (default `{ after: -1, limit: 100 }`),
653
+ * `maxPasses` (default `Infinity` — kill-switch for runaway loops),
654
+ * `streamLimit` (default 10), `eventLimit` (default 10),
655
+ * `leaseMillis` (default 10000).
656
+ *
657
+ * @example API mutations
658
+ * ```typescript
659
+ * await app.do("CreateItem", target, input);
660
+ * app.settle(); // non-blocking, returns immediately
661
+ *
662
+ * app.on("settled", (drain) => {
663
+ * // notify SSE clients, invalidate caches, etc.
664
+ * });
665
+ * ```
666
+ *
667
+ * @see {@link drain} for single synchronous drain cycles
668
+ * @see {@link correlate} for manual correlation
669
+ */
670
+ settle(options?: SettleOptions): void;
671
+ }
672
+ //# sourceMappingURL=act.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../../src/act.ts"],"names":[],"mappings":"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"}