@tasker-systems/tasker 0.1.0-alpha.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.
@@ -0,0 +1,4013 @@
1
+ import { T as TaskerRuntime, F as FfiDomainEvent, H as HandlerDefinitionDto } from './runtime-interface-CE4viUt7.js';
2
+ export { B as BaseTaskerRuntime, C as ClientHealthResponse, c as ClientPaginationInfo, d as ClientResult, e as ClientStepAuditResponse, f as ClientStepReadiness, g as ClientStepResponse, h as ClientTaskListResponse, i as ClientTaskRequest, j as ClientTaskResponse, D as DependencyResult, a as FfiBootstrapConfig, b as FfiBootstrapResult, k as FfiDispatchMetrics, L as FfiLogFields, l as FfiStepEvent, q as FfiStopResult, W as FfiWorkerStatus, m as HandlerDefinition, O as OrchestrationMetadata, R as RetryConfiguration, S as StepDefinition, n as StepExecutionError, o as StepExecutionMetadata, p as StepExecutionResult, r as Task, s as WorkflowStep } from './runtime-interface-CE4viUt7.js';
3
+ import { S as StepHandlerResult, a as StepHandler, B as BatchWorkerConfig, b as StepContext, E as ExecutableHandler, c as StepHandlerClass, T as TaskerEventEmitter, d as EventPoller, e as StepExecutionSubscriber, f as EventSystem } from './index-B3BcknlZ.js';
4
+ export { y as ErrorCallback, I as ErrorType, n as EventName, o as EventNames, z as EventPollerConfig, F as EventSystemConfig, G as EventSystemStats, A as MetricsCallback, p as MetricsEventName, q as MetricsEventNames, M as MetricsPayload, P as PollerCyclePayload, r as PollerEventName, s as PollerEventNames, C as PollerState, g as StepCompletionSentPayload, L as StepContextParams, D as StepEventCallback, t as StepEventName, u as StepEventNames, h as StepExecutionCompletedPayload, i as StepExecutionFailedPayload, j as StepExecutionReceivedPayload, k as StepExecutionStartedPayload, H as StepExecutionSubscriberConfig, N as StepHandlerResultParams, l as TaskerEventMap, W as WorkerErrorPayload, v as WorkerEventName, w as WorkerEventNames, m as WorkerEventPayload, x as createEventPoller, J as isStandardErrorType, K as isTypicallyRetryable } from './index-B3BcknlZ.js';
5
+ import { FfiLayerConfig } from './ffi/index.js';
6
+ export { BunRuntime, DenoRuntime, FfiLayer, NodeRuntime, RuntimeInfo, RuntimeType, detectRuntime, getLibraryPath, getRuntimeInfo, isBun, isDeno, isNode } from './ffi/index.js';
7
+ import { Logger } from 'pino';
8
+ import 'eventemitter3';
9
+
10
+ /**
11
+ * Bootstrap configuration and result types.
12
+ *
13
+ * These types extend the FFI types with TypeScript-friendly interfaces
14
+ * for worker lifecycle management.
15
+ */
16
+
17
+ /**
18
+ * Configuration for worker bootstrap.
19
+ *
20
+ * Matches Python's BootstrapConfig and Ruby's bootstrap options.
21
+ */
22
+ interface BootstrapConfig {
23
+ /** Optional worker ID. Auto-generated if not provided. */
24
+ workerId?: string;
25
+ /** Task namespace this worker handles (default: "default"). */
26
+ namespace?: string;
27
+ /** Path to custom configuration file (TOML). */
28
+ configPath?: string;
29
+ /** Log level: trace, debug, info, warn, error (default: "info"). */
30
+ logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error';
31
+ /** Database URL override. */
32
+ databaseUrl?: string;
33
+ }
34
+ /**
35
+ * Result from worker bootstrap.
36
+ *
37
+ * Contains information about the bootstrapped worker instance.
38
+ */
39
+ interface BootstrapResult {
40
+ /** Whether bootstrap was successful. */
41
+ success: boolean;
42
+ /** Current status (started, already_running, error). */
43
+ status: 'started' | 'already_running' | 'error';
44
+ /** Human-readable status message. */
45
+ message: string;
46
+ /** Unique identifier for this worker instance. */
47
+ workerId?: string;
48
+ /** Error message if bootstrap failed. */
49
+ error?: string;
50
+ }
51
+ /**
52
+ * Current worker status.
53
+ *
54
+ * Contains detailed information about the worker's state and resources.
55
+ */
56
+ interface WorkerStatus {
57
+ /** Whether the status query succeeded. */
58
+ success: boolean;
59
+ /** Whether the worker is currently running. */
60
+ running: boolean;
61
+ /** Current status string. */
62
+ status?: string;
63
+ /** Worker ID if running. */
64
+ workerId?: string;
65
+ /** Current environment (test, development, production). */
66
+ environment?: string;
67
+ /** Internal worker core status. */
68
+ workerCoreStatus?: string;
69
+ /** Whether the web API is enabled. */
70
+ webApiEnabled?: boolean;
71
+ /** List of task namespaces this worker handles. */
72
+ supportedNamespaces?: string[];
73
+ /** Total database connection pool size. */
74
+ databasePoolSize?: number;
75
+ /** Number of idle database connections. */
76
+ databasePoolIdle?: number;
77
+ }
78
+ /**
79
+ * Result from stopping the worker.
80
+ */
81
+ interface StopResult {
82
+ /** Whether the stop was successful. */
83
+ success: boolean;
84
+ /** Current status (stopped, not_running, error). */
85
+ status: 'stopped' | 'not_running' | 'error';
86
+ /** Human-readable status message. */
87
+ message: string;
88
+ /** Worker ID that was stopped. */
89
+ workerId?: string;
90
+ /** Error message if stop failed. */
91
+ error?: string;
92
+ }
93
+
94
+ /**
95
+ * Bootstrap API for TypeScript workers.
96
+ *
97
+ * High-level TypeScript API for worker lifecycle management.
98
+ * Wraps FFI calls with type-safe interfaces and error handling.
99
+ *
100
+ * Matches Python's bootstrap.py and Ruby's bootstrap.rb (TAS-92 aligned).
101
+ *
102
+ * All functions require an explicit runtime parameter. Use FfiLayer to load
103
+ * the runtime before calling these functions.
104
+ */
105
+
106
+ /**
107
+ * Initialize the worker system.
108
+ *
109
+ * This function bootstraps the full tasker-worker system, including:
110
+ * - Creating a Tokio runtime for async operations
111
+ * - Connecting to the database
112
+ * - Setting up the FFI dispatch channel for step events
113
+ * - Subscribing to domain events
114
+ *
115
+ * @param config - Optional bootstrap configuration
116
+ * @param runtime - The loaded FFI runtime (required)
117
+ * @returns BootstrapResult with worker details and status
118
+ * @throws Error if bootstrap fails critically
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const ffiLayer = new FfiLayer();
123
+ * await ffiLayer.load();
124
+ * const result = await bootstrapWorker({ namespace: 'payments' }, ffiLayer.getRuntime());
125
+ * console.log(`Worker ${result.workerId} started`);
126
+ * ```
127
+ */
128
+ declare function bootstrapWorker(config: BootstrapConfig | undefined, runtime: TaskerRuntime): Promise<BootstrapResult>;
129
+ /**
130
+ * Stop the worker system gracefully.
131
+ *
132
+ * This function stops the worker system and releases all resources.
133
+ * Safe to call even if the worker is not running.
134
+ *
135
+ * @param runtime - The loaded FFI runtime (optional - returns success if not loaded)
136
+ * @returns StopResult indicating the outcome
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * const result = stopWorker(runtime);
141
+ * if (result.success) {
142
+ * console.log('Worker stopped successfully');
143
+ * }
144
+ * ```
145
+ */
146
+ declare function stopWorker(runtime?: TaskerRuntime): StopResult;
147
+ /**
148
+ * Get the current worker system status.
149
+ *
150
+ * Returns detailed information about the worker's current state,
151
+ * including resource usage and operational status.
152
+ *
153
+ * @param runtime - The loaded FFI runtime (optional - returns stopped if not loaded)
154
+ * @returns WorkerStatus with current state and metrics
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const status = getWorkerStatus(runtime);
159
+ * if (status.running) {
160
+ * console.log(`Pool size: ${status.databasePoolSize}`);
161
+ * } else {
162
+ * console.log(`Worker not running`);
163
+ * }
164
+ * ```
165
+ */
166
+ declare function getWorkerStatus(runtime?: TaskerRuntime): WorkerStatus;
167
+ /**
168
+ * Initiate graceful shutdown of the worker system.
169
+ *
170
+ * This function begins the graceful shutdown process, allowing
171
+ * in-flight operations to complete before fully stopping.
172
+ * Call stopWorker() after this to fully stop the worker.
173
+ *
174
+ * @param runtime - The loaded FFI runtime (optional - returns success if not loaded)
175
+ * @returns StopResult indicating the transition status
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * // Start graceful shutdown
180
+ * transitionToGracefulShutdown(runtime);
181
+ *
182
+ * // Wait for in-flight operations...
183
+ * await new Promise(resolve => setTimeout(resolve, 5000));
184
+ *
185
+ * // Fully stop
186
+ * stopWorker(runtime);
187
+ * ```
188
+ */
189
+ declare function transitionToGracefulShutdown(runtime?: TaskerRuntime): StopResult;
190
+ /**
191
+ * Check if the worker system is currently running.
192
+ *
193
+ * Lightweight check that doesn't query the full status.
194
+ *
195
+ * @param runtime - The loaded FFI runtime (optional - returns false if not loaded)
196
+ * @returns True if the worker is running
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * if (!isWorkerRunning(runtime)) {
201
+ * await bootstrapWorker(config, runtime);
202
+ * }
203
+ * ```
204
+ */
205
+ declare function isWorkerRunning(runtime?: TaskerRuntime): boolean;
206
+ /**
207
+ * Get version information for the worker system.
208
+ *
209
+ * @param runtime - The loaded FFI runtime (optional)
210
+ * @returns Version string from the Rust library
211
+ */
212
+ declare function getVersion(runtime?: TaskerRuntime): string;
213
+ /**
214
+ * Get detailed Rust library version.
215
+ *
216
+ * @param runtime - The loaded FFI runtime (optional)
217
+ * @returns Detailed version information
218
+ */
219
+ declare function getRustVersion(runtime?: TaskerRuntime): string;
220
+ /**
221
+ * Perform a health check on the FFI module.
222
+ *
223
+ * @param runtime - The loaded FFI runtime (optional - returns false if not loaded)
224
+ * @returns True if the FFI module is functional
225
+ */
226
+ declare function healthCheck(runtime?: TaskerRuntime): boolean;
227
+
228
+ /**
229
+ * API mixin for HTTP functionality.
230
+ *
231
+ * TAS-112: Composition Pattern - API Mixin
232
+ *
233
+ * This module provides the APIMixin class for step handlers that need HTTP
234
+ * functionality. Use via interface implementation with method binding.
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * class FetchUserHandler extends StepHandler implements APICapable {
239
+ * static handlerName = 'fetch_user';
240
+ * static baseUrl = 'https://api.example.com';
241
+ *
242
+ * // Bind APIMixin methods
243
+ * get = APIMixin.prototype.get.bind(this);
244
+ * apiSuccess = APIMixin.prototype.apiSuccess.bind(this);
245
+ * apiFailure = APIMixin.prototype.apiFailure.bind(this);
246
+ * // ... other required methods
247
+ *
248
+ * async call(context: StepContext): Promise<StepHandlerResult> {
249
+ * const response = await this.get('/users');
250
+ * if (response.ok) {
251
+ * return this.apiSuccess(response);
252
+ * }
253
+ * return this.apiFailure(response);
254
+ * }
255
+ * }
256
+ * ```
257
+ *
258
+ * @module handler/mixins/api
259
+ */
260
+
261
+ /**
262
+ * Response wrapper for API calls.
263
+ *
264
+ * Provides convenient access to response data and error classification.
265
+ */
266
+ declare class ApiResponse {
267
+ readonly statusCode: number;
268
+ readonly headers: Record<string, string>;
269
+ readonly body: unknown;
270
+ readonly rawResponse: Response;
271
+ constructor(response: Response, body?: unknown);
272
+ /**
273
+ * Check if the response indicates success (2xx status).
274
+ */
275
+ get ok(): boolean;
276
+ /**
277
+ * Check if the response indicates a client error (4xx status).
278
+ */
279
+ get isClientError(): boolean;
280
+ /**
281
+ * Check if the response indicates a server error (5xx status).
282
+ */
283
+ get isServerError(): boolean;
284
+ /**
285
+ * Check if the error should be retried.
286
+ */
287
+ get isRetryable(): boolean;
288
+ /**
289
+ * Get the Retry-After header value in seconds, if present.
290
+ */
291
+ get retryAfter(): number | null;
292
+ /**
293
+ * Convert the response to a dictionary for result output.
294
+ */
295
+ toDict(): Record<string, unknown>;
296
+ }
297
+ /**
298
+ * Interface for API-capable handlers.
299
+ *
300
+ * Implement this interface and bind APIMixin methods to get HTTP functionality.
301
+ */
302
+ interface APICapable {
303
+ /** Base URL for API calls */
304
+ baseUrl: string;
305
+ /** Default request timeout in milliseconds */
306
+ timeout: number;
307
+ /** Default headers to include in all requests */
308
+ defaultHeaders: Record<string, string>;
309
+ get(path: string, params?: Record<string, unknown>, headers?: Record<string, string>): Promise<ApiResponse>;
310
+ post(path: string, options?: {
311
+ body?: unknown;
312
+ json?: boolean;
313
+ headers?: Record<string, string>;
314
+ }): Promise<ApiResponse>;
315
+ put(path: string, options?: {
316
+ body?: unknown;
317
+ json?: boolean;
318
+ headers?: Record<string, string>;
319
+ }): Promise<ApiResponse>;
320
+ patch(path: string, options?: {
321
+ body?: unknown;
322
+ json?: boolean;
323
+ headers?: Record<string, string>;
324
+ }): Promise<ApiResponse>;
325
+ delete(path: string, headers?: Record<string, string>): Promise<ApiResponse>;
326
+ request(method: string, path: string, options?: RequestInit): Promise<ApiResponse>;
327
+ apiSuccess(response: ApiResponse, result?: Record<string, unknown>, includeResponse?: boolean): StepHandlerResult;
328
+ apiFailure(response: ApiResponse, message?: string): StepHandlerResult;
329
+ connectionError(error: Error, context?: string): StepHandlerResult;
330
+ timeoutError(error: Error, context?: string): StepHandlerResult;
331
+ }
332
+ /**
333
+ * Implementation of API methods.
334
+ *
335
+ * TAS-112: Use via interface implementation with method binding.
336
+ *
337
+ * Provides HTTP client functionality with automatic error classification,
338
+ * retry handling, and convenient methods for common HTTP operations.
339
+ */
340
+ declare class APIMixin implements APICapable {
341
+ static baseUrl: string;
342
+ static defaultTimeout: number;
343
+ static defaultHeaders: Record<string, string>;
344
+ get baseUrl(): string;
345
+ get timeout(): number;
346
+ get defaultHeaders(): Record<string, string>;
347
+ /**
348
+ * Make a GET request.
349
+ */
350
+ get(path: string, params?: Record<string, unknown>, headers?: Record<string, string>): Promise<ApiResponse>;
351
+ /**
352
+ * Make a POST request.
353
+ */
354
+ post(path: string, options?: {
355
+ body?: unknown;
356
+ json?: boolean;
357
+ headers?: Record<string, string>;
358
+ }): Promise<ApiResponse>;
359
+ /**
360
+ * Make a PUT request.
361
+ */
362
+ put(path: string, options?: {
363
+ body?: unknown;
364
+ json?: boolean;
365
+ headers?: Record<string, string>;
366
+ }): Promise<ApiResponse>;
367
+ /**
368
+ * Make a PATCH request.
369
+ */
370
+ patch(path: string, options?: {
371
+ body?: unknown;
372
+ json?: boolean;
373
+ headers?: Record<string, string>;
374
+ }): Promise<ApiResponse>;
375
+ /**
376
+ * Make a DELETE request.
377
+ */
378
+ delete(path: string, headers?: Record<string, string>): Promise<ApiResponse>;
379
+ /**
380
+ * Make an arbitrary HTTP request.
381
+ */
382
+ request(method: string, path: string, options?: RequestInit): Promise<ApiResponse>;
383
+ /**
384
+ * Create a success result from an API response.
385
+ */
386
+ apiSuccess(response: ApiResponse, result?: Record<string, unknown>, includeResponse?: boolean): StepHandlerResult;
387
+ /**
388
+ * Create a failure result from an API response.
389
+ */
390
+ apiFailure(response: ApiResponse, message?: string): StepHandlerResult;
391
+ /**
392
+ * Create a failure result from a connection error.
393
+ */
394
+ connectionError(error: Error, context?: string): StepHandlerResult;
395
+ /**
396
+ * Create a failure result from a timeout error.
397
+ */
398
+ timeoutError(error: Error, context?: string): StepHandlerResult;
399
+ private fetch;
400
+ private buildUrl;
401
+ private mergeHeaders;
402
+ private prepareBody;
403
+ private classifyError;
404
+ private formatErrorMessage;
405
+ private extractBodyErrorMessage;
406
+ }
407
+ /**
408
+ * Helper function to apply API methods to a handler instance.
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * class MyApiHandler extends StepHandler {
413
+ * constructor() {
414
+ * super();
415
+ * applyAPI(this);
416
+ * }
417
+ * }
418
+ * ```
419
+ */
420
+ declare function applyAPI<T extends object>(target: T): T & APICapable;
421
+
422
+ /**
423
+ * API handler for HTTP interactions.
424
+ *
425
+ * TAS-112: Composition Pattern (DEPRECATED CLASS)
426
+ *
427
+ * This module provides the ApiHandler class for backward compatibility.
428
+ * For new code, use the mixin pattern:
429
+ *
430
+ * @example Using APIMixin
431
+ * ```typescript
432
+ * import { StepHandler } from './base';
433
+ * import { APIMixin, APICapable, applyAPI } from './mixins/api';
434
+ *
435
+ * class FetchUserHandler extends StepHandler implements APICapable {
436
+ * static handlerName = 'fetch_user';
437
+ * static baseUrl = 'https://api.example.com';
438
+ *
439
+ * constructor() {
440
+ * super();
441
+ * applyAPI(this);
442
+ * }
443
+ *
444
+ * async call(context: StepContext): Promise<StepHandlerResult> {
445
+ * const response = await this.get('/users');
446
+ * if (response.ok) {
447
+ * return this.apiSuccess(response);
448
+ * }
449
+ * return this.apiFailure(response);
450
+ * }
451
+ * }
452
+ * ```
453
+ *
454
+ * @module handler/api
455
+ */
456
+
457
+ /**
458
+ * Base class for HTTP API step handlers.
459
+ *
460
+ * TAS-112: This class is provided for backward compatibility.
461
+ * For new code, prefer using APIMixin directly with applyAPI().
462
+ *
463
+ * Provides HTTP client functionality with automatic error classification,
464
+ * retry handling, and convenient methods for common HTTP operations.
465
+ *
466
+ * Uses native fetch API (available in Bun and Node.js 18+).
467
+ *
468
+ * @example
469
+ * ```typescript
470
+ * class PaymentApiHandler extends ApiHandler {
471
+ * static handlerName = 'process_payment';
472
+ * static baseUrl = 'https://payments.example.com/api/v1';
473
+ * static defaultHeaders = { 'X-API-Key': 'secret' };
474
+ *
475
+ * async call(context: StepContext): Promise<StepHandlerResult> {
476
+ * const paymentData = context.inputData['payment'];
477
+ * const response = await this.post('/payments', { body: paymentData });
478
+ * if (response.ok) {
479
+ * return this.apiSuccess(response);
480
+ * }
481
+ * return this.apiFailure(response);
482
+ * }
483
+ * }
484
+ * ```
485
+ */
486
+ declare abstract class ApiHandler extends StepHandler {
487
+ /** Base URL for API calls. Override in subclasses. */
488
+ static baseUrl: string;
489
+ /** Default request timeout in milliseconds. */
490
+ static defaultTimeout: number;
491
+ /** Default headers to include in all requests. */
492
+ static defaultHeaders: Record<string, string>;
493
+ private _apiMixin;
494
+ private getApiMixin;
495
+ get capabilities(): string[];
496
+ /**
497
+ * Get the base URL for this handler.
498
+ */
499
+ get baseUrl(): string;
500
+ /**
501
+ * Get the default timeout for this handler.
502
+ */
503
+ get timeout(): number;
504
+ /**
505
+ * Get the default headers for this handler.
506
+ */
507
+ get defaultHeaders(): Record<string, string>;
508
+ protected get(path: string, params?: Record<string, unknown>, headers?: Record<string, string>): Promise<ApiResponse>;
509
+ protected post(path: string, options?: {
510
+ body?: unknown;
511
+ json?: boolean;
512
+ headers?: Record<string, string>;
513
+ }): Promise<ApiResponse>;
514
+ protected put(path: string, options?: {
515
+ body?: unknown;
516
+ json?: boolean;
517
+ headers?: Record<string, string>;
518
+ }): Promise<ApiResponse>;
519
+ protected patch(path: string, options?: {
520
+ body?: unknown;
521
+ json?: boolean;
522
+ headers?: Record<string, string>;
523
+ }): Promise<ApiResponse>;
524
+ protected delete(path: string, headers?: Record<string, string>): Promise<ApiResponse>;
525
+ protected request(method: string, path: string, options?: RequestInit): Promise<ApiResponse>;
526
+ protected apiSuccess(response: ApiResponse, result?: Record<string, unknown>, includeResponse?: boolean): StepHandlerResult;
527
+ protected apiFailure(response: ApiResponse, message?: string): StepHandlerResult;
528
+ protected connectionError(error: Error, context?: string): StepHandlerResult;
529
+ protected timeoutError(error: Error, context?: string): StepHandlerResult;
530
+ }
531
+
532
+ /**
533
+ * Batch processing types for cursor-based batch operations.
534
+ *
535
+ * These types support the analyzer/worker pattern for processing
536
+ * large datasets in parallel batches.
537
+ *
538
+ * Matches Python's batch processing types and Ruby's batch types (TAS-92 aligned).
539
+ *
540
+ * ## FFI Boundary Types (TAS-112/TAS-123)
541
+ *
542
+ * This module includes types that cross the Rust ↔ TypeScript FFI boundary:
543
+ *
544
+ * - `RustCursorConfig` - Cursor configuration with flexible cursor types
545
+ * - `BatchProcessingOutcome` - Discriminated union for batch processing decisions
546
+ * - `RustBatchWorkerInputs` - Worker initialization inputs from Rust orchestration
547
+ * - `BatchMetadata` - Batch processing metadata from template configuration
548
+ *
549
+ * These types are serialized by Rust and deserialized by TypeScript workers.
550
+ * They must remain compatible with Rust's serde serialization format.
551
+ *
552
+ * @module types/batch
553
+ */
554
+ /**
555
+ * Configuration for cursor-based batch processing.
556
+ *
557
+ * Defines a range of items to process in a batch worker step.
558
+ */
559
+ interface CursorConfig {
560
+ /** Starting cursor position (inclusive) */
561
+ startCursor: number;
562
+ /** Ending cursor position (exclusive) */
563
+ endCursor: number;
564
+ /** Step size for iteration (usually 1) */
565
+ stepSize: number;
566
+ /** Additional metadata for this cursor range */
567
+ metadata: Record<string, unknown>;
568
+ }
569
+ /**
570
+ * Outcome from a batch analyzer handler.
571
+ *
572
+ * Batch analyzers return this to define the cursor ranges that will
573
+ * spawn parallel batch worker steps.
574
+ */
575
+ interface BatchAnalyzerOutcome {
576
+ /** List of cursor configurations for batch workers */
577
+ cursorConfigs: CursorConfig[];
578
+ /** Total number of items to process (for progress tracking) */
579
+ totalItems: number | null;
580
+ /** Metadata to pass to all batch workers */
581
+ batchMetadata: Record<string, unknown>;
582
+ }
583
+ /**
584
+ * Context for a batch worker step.
585
+ *
586
+ * Provides information about the specific batch this worker should process,
587
+ * including checkpoint data from previous yields (TAS-125).
588
+ */
589
+ interface BatchWorkerContext {
590
+ /** Unique identifier for this batch */
591
+ batchId: string;
592
+ /** Cursor configuration for this batch */
593
+ cursorConfig: CursorConfig;
594
+ /** Index of this batch (0-based) */
595
+ batchIndex: number;
596
+ /** Total number of batches */
597
+ totalBatches: number;
598
+ /** Metadata from the analyzer */
599
+ batchMetadata: Record<string, unknown>;
600
+ /** TAS-125: Checkpoint data from previous yields */
601
+ checkpoint: Record<string, unknown>;
602
+ /** Convenience accessor for start cursor */
603
+ readonly startCursor: number;
604
+ /** Convenience accessor for end cursor */
605
+ readonly endCursor: number;
606
+ /** Convenience accessor for step size */
607
+ readonly stepSize: number;
608
+ /** TAS-125: Get checkpoint cursor from previous yield */
609
+ readonly checkpointCursor: number | string | Record<string, unknown> | undefined;
610
+ /** TAS-125: Get accumulated results from previous checkpoint yield */
611
+ readonly accumulatedResults: Record<string, unknown> | undefined;
612
+ /** TAS-125: Get items processed count from checkpoint */
613
+ readonly checkpointItemsProcessed: number;
614
+ /** TAS-125: Check if checkpoint exists */
615
+ hasCheckpoint(): boolean;
616
+ }
617
+ /**
618
+ * Outcome from a batch worker step.
619
+ *
620
+ * Batch workers return this to report progress and results.
621
+ */
622
+ interface BatchWorkerOutcome {
623
+ /** Total items processed in this batch */
624
+ itemsProcessed: number;
625
+ /** Items that succeeded */
626
+ itemsSucceeded: number;
627
+ /** Items that failed */
628
+ itemsFailed: number;
629
+ /** Items that were skipped */
630
+ itemsSkipped: number;
631
+ /** Individual item results */
632
+ results: Array<Record<string, unknown>>;
633
+ /** Individual item errors */
634
+ errors: Array<Record<string, unknown>>;
635
+ /** Last cursor position processed */
636
+ lastCursor: number | null;
637
+ /** Additional batch metadata */
638
+ batchMetadata: Record<string, unknown>;
639
+ }
640
+ /**
641
+ * Create a BatchWorkerContext from raw batch data.
642
+ *
643
+ * Handles both formats:
644
+ * - Nested: { batch_id, cursor_config: { start_cursor, end_cursor, ... } }
645
+ * - Flat: { batch_id, start_cursor, end_cursor, ... }
646
+ *
647
+ * TAS-125: Also extracts checkpoint data if present.
648
+ *
649
+ * @internal
650
+ */
651
+ declare function createBatchWorkerContext(batchData: Record<string, unknown>, checkpoint?: Record<string, unknown>): BatchWorkerContext;
652
+ /**
653
+ * Cursor configuration for a single batch's position and range.
654
+ *
655
+ * Matches Rust's `CursorConfig` in `tasker-shared/src/messaging/execution_types.rs`.
656
+ *
657
+ * ## Flexible Cursor Types
658
+ *
659
+ * Unlike the simpler `CursorConfig` interface (which uses `number`),
660
+ * this type supports flexible cursor values that can be:
661
+ * - Integer for record IDs: `123`
662
+ * - String for timestamps: `"2025-11-01T00:00:00Z"`
663
+ * - Object for composite keys: `{"page": 1, "offset": 0}`
664
+ *
665
+ * This enables cursor-based pagination across diverse data sources.
666
+ *
667
+ * @example
668
+ * ```typescript
669
+ * // Integer cursors (most common)
670
+ * const intCursor: RustCursorConfig = {
671
+ * batch_id: "batch_001",
672
+ * start_cursor: 0,
673
+ * end_cursor: 1000,
674
+ * batch_size: 1000,
675
+ * };
676
+ *
677
+ * // Timestamp cursors
678
+ * const timestampCursor: RustCursorConfig = {
679
+ * batch_id: "batch_001",
680
+ * start_cursor: "2025-01-01T00:00:00Z",
681
+ * end_cursor: "2025-01-02T00:00:00Z",
682
+ * batch_size: 86400, // seconds in a day
683
+ * };
684
+ *
685
+ * // Composite cursors
686
+ * const compositeCursor: RustCursorConfig = {
687
+ * batch_id: "batch_001",
688
+ * start_cursor: { page: 1, offset: 0 },
689
+ * end_cursor: { page: 10, offset: 0 },
690
+ * batch_size: 1000,
691
+ * };
692
+ * ```
693
+ */
694
+ interface RustCursorConfig {
695
+ /** Batch identifier (e.g., "batch_001", "batch_002") */
696
+ batch_id: string;
697
+ /**
698
+ * Starting position for this batch (inclusive).
699
+ *
700
+ * Type depends on cursor strategy:
701
+ * - `number` for record IDs
702
+ * - `string` for timestamps or UUIDs
703
+ * - `object` for composite keys
704
+ */
705
+ start_cursor: unknown;
706
+ /**
707
+ * Ending position for this batch (exclusive).
708
+ *
709
+ * Workers process items from `start_cursor` (inclusive)
710
+ * up to but not including `end_cursor`.
711
+ */
712
+ end_cursor: unknown;
713
+ /** Number of items in this batch (for progress reporting) */
714
+ batch_size: number;
715
+ }
716
+ /**
717
+ * Failure strategy for batch processing.
718
+ *
719
+ * Matches Rust's `FailureStrategy` enum in `task_template.rs`.
720
+ */
721
+ type FailureStrategy = 'continue_on_failure' | 'fail_fast' | 'isolate';
722
+ /**
723
+ * Batch processing metadata from template configuration.
724
+ *
725
+ * Matches Rust's `BatchMetadata` in `tasker-shared/src/models/core/batch_worker.rs`.
726
+ *
727
+ * This structure extracts relevant template configuration that workers
728
+ * need during execution. Workers don't need parallelism settings or
729
+ * batch size calculation logic - just execution parameters.
730
+ */
731
+ interface BatchMetadata {
732
+ /**
733
+ * Database field name used for cursor-based pagination.
734
+ *
735
+ * Workers use this to construct queries like:
736
+ * `WHERE cursor_field > start_cursor AND cursor_field <= end_cursor`
737
+ *
738
+ * Common values: "id", "created_at", "sequence_number"
739
+ */
740
+ cursor_field: string;
741
+ /**
742
+ * How this worker should handle failures during batch processing.
743
+ *
744
+ * - `continue_on_failure`: Log errors, continue processing remaining items
745
+ * - `fail_fast`: Stop immediately on first error
746
+ * - `isolate`: Mark batch for manual investigation
747
+ */
748
+ failure_strategy: FailureStrategy;
749
+ }
750
+ /**
751
+ * Initialization inputs for batch worker instances.
752
+ *
753
+ * Matches Rust's `BatchWorkerInputs` in `tasker-shared/src/models/core/batch_worker.rs`.
754
+ *
755
+ * This structure is serialized to JSONB by Rust orchestration and stored
756
+ * in `workflow_steps.inputs` for dynamically created batch workers.
757
+ *
758
+ * @example
759
+ * ```typescript
760
+ * // In a batch worker handler
761
+ * async call(context: StepContext): Promise<StepHandlerResult> {
762
+ * const inputs = context.stepInputs as RustBatchWorkerInputs;
763
+ *
764
+ * // Check for no-op placeholder first
765
+ * if (inputs.is_no_op) {
766
+ * return this.success({
767
+ * batch_id: inputs.cursor.batch_id,
768
+ * no_op: true,
769
+ * message: 'No batches to process',
770
+ * });
771
+ * }
772
+ *
773
+ * // Process the batch using cursor bounds
774
+ * const { start_cursor, end_cursor } = inputs.cursor;
775
+ * // ... process items in range
776
+ * }
777
+ * ```
778
+ */
779
+ interface RustBatchWorkerInputs {
780
+ /**
781
+ * Cursor configuration defining this worker's processing range.
782
+ *
783
+ * Created by the batchable handler after analyzing dataset size.
784
+ */
785
+ cursor: RustCursorConfig;
786
+ /**
787
+ * Batch processing metadata from template configuration.
788
+ *
789
+ * Provides checkpointing frequency, cursor field, and failure strategy.
790
+ */
791
+ batch_metadata: BatchMetadata;
792
+ /**
793
+ * Explicit flag indicating if this is a no-op/placeholder worker.
794
+ *
795
+ * Set by orchestration based on BatchProcessingOutcome type:
796
+ * - `true` for NoBatches outcome (placeholder worker)
797
+ * - `false` for CreateBatches outcome (real worker with data)
798
+ *
799
+ * Workers should check this flag FIRST before any processing logic.
800
+ * If `true`, immediately return success without processing.
801
+ */
802
+ is_no_op: boolean;
803
+ }
804
+ /**
805
+ * No batches needed - process as single step or skip.
806
+ *
807
+ * Returned when:
808
+ * - Dataset is too small to warrant batching
809
+ * - Data doesn't meet batching criteria
810
+ * - Batch processing not applicable for this execution
811
+ *
812
+ * Serialization format: `{ "type": "no_batches" }`
813
+ */
814
+ interface NoBatchesOutcome {
815
+ type: 'no_batches';
816
+ }
817
+ /**
818
+ * Create batch worker steps from template.
819
+ *
820
+ * The orchestration system will:
821
+ * 1. Instantiate N workers from the template step
822
+ * 2. Assign each worker a unique cursor config
823
+ * 3. Create DAG edges from batchable step to workers
824
+ * 4. Enqueue workers for parallel execution
825
+ *
826
+ * Serialization format:
827
+ * ```json
828
+ * {
829
+ * "type": "create_batches",
830
+ * "worker_template_name": "batch_worker_template",
831
+ * "worker_count": 5,
832
+ * "cursor_configs": [...],
833
+ * "total_items": 5000
834
+ * }
835
+ * ```
836
+ */
837
+ interface CreateBatchesOutcome {
838
+ type: 'create_batches';
839
+ /**
840
+ * Template step name to use for creating workers.
841
+ *
842
+ * Must match a step definition in the template with `type: batch_worker`.
843
+ * The system creates multiple instances with generated names like:
844
+ * - `{template_name}_001`
845
+ * - `{template_name}_002`
846
+ */
847
+ worker_template_name: string;
848
+ /**
849
+ * Number of worker instances to create.
850
+ *
851
+ * Typically calculated based on dataset size / batch_size.
852
+ */
853
+ worker_count: number;
854
+ /**
855
+ * Initial cursor positions for each batch.
856
+ *
857
+ * Each worker receives one cursor config that defines its
858
+ * processing boundaries. Length must equal `worker_count`.
859
+ */
860
+ cursor_configs: RustCursorConfig[];
861
+ /**
862
+ * Total items to process across all batches.
863
+ *
864
+ * Used for progress tracking and observability.
865
+ */
866
+ total_items: number;
867
+ }
868
+ /**
869
+ * Outcome of a batchable step that determines batch worker creation.
870
+ *
871
+ * Matches Rust's `BatchProcessingOutcome` enum in
872
+ * `tasker-shared/src/messaging/execution_types.rs`.
873
+ *
874
+ * This discriminated union enables type-safe pattern matching:
875
+ *
876
+ * @example
877
+ * ```typescript
878
+ * function handleOutcome(outcome: BatchProcessingOutcome): void {
879
+ * switch (outcome.type) {
880
+ * case 'no_batches':
881
+ * console.log('No batches needed');
882
+ * break;
883
+ * case 'create_batches':
884
+ * console.log(`Creating ${outcome.worker_count} workers`);
885
+ * console.log(`Total items: ${outcome.total_items}`);
886
+ * break;
887
+ * default: {
888
+ * const _exhaustive: never = outcome;
889
+ * throw new Error(`Unhandled outcome type: ${_exhaustive}`);
890
+ * }
891
+ * }
892
+ * }
893
+ * ```
894
+ */
895
+ type BatchProcessingOutcome = NoBatchesOutcome | CreateBatchesOutcome;
896
+ /**
897
+ * Create a NoBatches outcome.
898
+ *
899
+ * Use when batching is not needed or applicable.
900
+ *
901
+ * @returns A NoBatchesOutcome object
902
+ */
903
+ declare function noBatches(): NoBatchesOutcome;
904
+ /**
905
+ * Create a CreateBatches outcome with specified configuration.
906
+ *
907
+ * @param workerTemplateName - Name of the template step to instantiate
908
+ * @param workerCount - Number of workers to create
909
+ * @param cursorConfigs - Cursor configuration for each worker
910
+ * @param totalItems - Total number of items to process
911
+ * @returns A CreateBatchesOutcome object
912
+ *
913
+ * @example
914
+ * ```typescript
915
+ * const outcome = createBatches(
916
+ * 'process_csv_batch',
917
+ * 3,
918
+ * [
919
+ * { batch_id: '001', start_cursor: 0, end_cursor: 1000, batch_size: 1000 },
920
+ * { batch_id: '002', start_cursor: 1000, end_cursor: 2000, batch_size: 1000 },
921
+ * { batch_id: '003', start_cursor: 2000, end_cursor: 3000, batch_size: 1000 },
922
+ * ],
923
+ * 3000
924
+ * );
925
+ * ```
926
+ */
927
+ declare function createBatches(workerTemplateName: string, workerCount: number, cursorConfigs: RustCursorConfig[], totalItems: number): CreateBatchesOutcome;
928
+ /**
929
+ * Type guard to check if an outcome is NoBatches.
930
+ */
931
+ declare function isNoBatches(outcome: BatchProcessingOutcome): outcome is NoBatchesOutcome;
932
+ /**
933
+ * Type guard to check if an outcome is CreateBatches.
934
+ */
935
+ declare function isCreateBatches(outcome: BatchProcessingOutcome): outcome is CreateBatchesOutcome;
936
+ /**
937
+ * Result from aggregating multiple batch worker results.
938
+ *
939
+ * Cross-language standard: matches Python's aggregate_worker_results output
940
+ * and Ruby's aggregate_batch_worker_results.
941
+ *
942
+ * TAS-112: Standardized aggregation result structure.
943
+ */
944
+ interface BatchAggregationResult {
945
+ /** Total items processed across all batches */
946
+ total_processed: number;
947
+ /** Total items that succeeded */
948
+ total_succeeded: number;
949
+ /** Total items that failed */
950
+ total_failed: number;
951
+ /** Total items that were skipped */
952
+ total_skipped: number;
953
+ /** Number of batch workers that ran */
954
+ batch_count: number;
955
+ /** Success rate (0.0 to 1.0) */
956
+ success_rate: number;
957
+ /** Collected errors from all batches (limited) */
958
+ errors: Array<Record<string, unknown>>;
959
+ /** Total error count (may exceed errors array length) */
960
+ error_count: number;
961
+ }
962
+ /**
963
+ * Aggregate results from multiple batch workers.
964
+ *
965
+ * Cross-language standard: matches Python's `Batchable.aggregate_worker_results`
966
+ * and Ruby's `aggregate_batch_worker_results`.
967
+ *
968
+ * @param workerResults - Array of results from batch worker steps
969
+ * @param maxErrors - Maximum number of errors to collect (default: 100)
970
+ * @returns Aggregated summary of all batch processing
971
+ *
972
+ * @example
973
+ * ```typescript
974
+ * // In an aggregator handler
975
+ * const workerResults = Object.values(context.previousResults)
976
+ * .filter(r => r?.batch_worker);
977
+ * const summary = aggregateBatchResults(workerResults);
978
+ * return this.success(summary);
979
+ * ```
980
+ */
981
+ declare function aggregateBatchResults(workerResults: Array<Record<string, unknown> | null | undefined>, maxErrors?: number): BatchAggregationResult;
982
+
983
+ /**
984
+ * Represents the aggregation scenario for batch processing convergence steps.
985
+ *
986
+ * Cross-language standard: matches Ruby's BatchAggregationScenario,
987
+ * Python's BatchAggregationScenario, and Rust's BatchAggregationScenario enum.
988
+ *
989
+ * There are two scenarios:
990
+ * - **NoBatches**: The batchable step returned `noBatches()`, no workers were created.
991
+ * The convergence step should read results directly from the batchable step.
992
+ * - **WithBatches**: Workers were created and processed batches. The convergence
993
+ * step should aggregate results from all batch workers.
994
+ */
995
+ interface BatchAggregationScenario {
996
+ /** True if this is a NoBatches scenario. */
997
+ isNoBatches: boolean;
998
+ /** Result from the batchable step (always present). */
999
+ batchableResult: Record<string, unknown>;
1000
+ /** Dict of worker_name -> result (empty for NoBatches). */
1001
+ batchResults: Record<string, Record<string, unknown>>;
1002
+ /** Number of batch workers (0 for NoBatches). */
1003
+ workerCount: number;
1004
+ }
1005
+ /**
1006
+ * Mixin interface for batch processing capabilities.
1007
+ *
1008
+ * TypeScript implementation using interface + method binding pattern
1009
+ * (since TS doesn't have true mixins like Python/Ruby).
1010
+ *
1011
+ * Matches Python's Batchable mixin and Ruby's Batchable module (TAS-92 aligned).
1012
+ */
1013
+ interface Batchable {
1014
+ createCursorConfig(start: number, end: number, stepSize?: number, metadata?: Record<string, unknown>): CursorConfig;
1015
+ createCursorRanges(totalItems: number, batchSize: number, stepSize?: number, maxBatches?: number): CursorConfig[];
1016
+ /**
1017
+ * Create cursor configurations for a specific number of workers.
1018
+ *
1019
+ * Ruby-style method that divides items into worker_count roughly equal ranges.
1020
+ * Use this when you know the desired number of workers rather than batch size.
1021
+ *
1022
+ * Cross-language standard: matches Ruby's create_cursor_configs(total_items, worker_count).
1023
+ */
1024
+ createCursorConfigs(totalItems: number, workerCount: number): BatchWorkerConfig[];
1025
+ createBatchOutcome(totalItems: number, batchSize: number, stepSize?: number, batchMetadata?: Record<string, unknown>): BatchAnalyzerOutcome;
1026
+ createWorkerOutcome(itemsProcessed: number, itemsSucceeded?: number, itemsFailed?: number, itemsSkipped?: number, results?: Array<Record<string, unknown>>, errors?: Array<Record<string, unknown>>, lastCursor?: number | null, batchMetadata?: Record<string, unknown>): BatchWorkerOutcome;
1027
+ getBatchContext(context: StepContext): BatchWorkerContext | null;
1028
+ /**
1029
+ * Get Rust batch worker inputs from step context.
1030
+ *
1031
+ * Returns the BatchWorkerInputs structure from workflow_step.inputs,
1032
+ * which contains cursor config, batch metadata, and no-op flag.
1033
+ *
1034
+ * Cross-language standard: matches Ruby's get_batch_context pattern.
1035
+ */
1036
+ getBatchWorkerInputs(context: StepContext): Partial<RustBatchWorkerInputs> | null;
1037
+ /**
1038
+ * Handle no-op placeholder worker scenario.
1039
+ *
1040
+ * Returns a success result if the worker is a no-op placeholder,
1041
+ * otherwise returns null to allow normal processing to continue.
1042
+ *
1043
+ * Cross-language standard: matches Ruby's handle_no_op_worker.
1044
+ */
1045
+ handleNoOpWorker(context: StepContext): StepHandlerResult | null;
1046
+ batchAnalyzerSuccess(outcome: BatchAnalyzerOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1047
+ batchWorkerSuccess(outcome: BatchWorkerOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1048
+ /**
1049
+ * TAS-125: Yield checkpoint for batch processing.
1050
+ *
1051
+ * Use this method when your handler needs to persist progress and be
1052
+ * re-dispatched for continued processing. Unlike batchWorkerSuccess,
1053
+ * this does NOT complete the step.
1054
+ *
1055
+ * @param cursor - Position to resume from (number, string, or object)
1056
+ * @param itemsProcessed - Total items processed so far (cumulative)
1057
+ * @param accumulatedResults - Partial aggregations to carry forward
1058
+ * @returns A StepHandlerResult with checkpoint_yield type
1059
+ */
1060
+ checkpointYield(cursor: number | string | Record<string, unknown>, itemsProcessed: number, accumulatedResults?: Record<string, unknown>): StepHandlerResult;
1061
+ /**
1062
+ * Detect batch aggregation scenario from dependency results.
1063
+ *
1064
+ * Cross-language standard: matches Ruby's detect_aggregation_scenario,
1065
+ * Python's detect_aggregation_scenario, and Rust's BatchAggregationScenario::detect.
1066
+ */
1067
+ detectAggregationScenario(dependencyResults: Record<string, unknown>, batchableStepName: string, batchWorkerPrefix: string): BatchAggregationScenario;
1068
+ /**
1069
+ * Create a success result for NoBatches aggregation scenario.
1070
+ *
1071
+ * Cross-language standard: matches Ruby's no_batches_aggregation_result
1072
+ * and Python's no_batches_aggregation_result.
1073
+ */
1074
+ noBatchesAggregationResult(zeroMetrics?: Record<string, unknown>): StepHandlerResult;
1075
+ /**
1076
+ * Aggregate batch worker results handling both scenarios.
1077
+ *
1078
+ * Cross-language standard: matches Ruby's aggregate_batch_worker_results
1079
+ * and Python's aggregate_batch_worker_results.
1080
+ */
1081
+ aggregateBatchWorkerResults(scenario: BatchAggregationScenario, zeroMetrics?: Record<string, unknown>, aggregationFn?: (batchResults: Record<string, Record<string, unknown>>) => Record<string, unknown>): StepHandlerResult;
1082
+ }
1083
+ /**
1084
+ * Implementation of Batchable methods.
1085
+ *
1086
+ * Use this class to add batch processing capabilities to your handlers.
1087
+ * The methods can be bound to handler instances or used as a mixin.
1088
+ *
1089
+ * @example Analyzer using method binding
1090
+ * ```typescript
1091
+ * class ProductAnalyzer extends StepHandler implements Batchable {
1092
+ * // Bind Batchable methods to this instance
1093
+ * createBatchOutcome = BatchableMixin.prototype.createBatchOutcome.bind(this);
1094
+ * batchAnalyzerSuccess = BatchableMixin.prototype.batchAnalyzerSuccess.bind(this);
1095
+ * // ... other required Batchable methods
1096
+ *
1097
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1098
+ * const total = context.inputData['product_count'] as number;
1099
+ * const outcome = this.createBatchOutcome(total, 100);
1100
+ * return this.batchAnalyzerSuccess(outcome);
1101
+ * }
1102
+ * }
1103
+ * ```
1104
+ *
1105
+ * @example Worker using method binding
1106
+ * ```typescript
1107
+ * class ProductWorker extends StepHandler implements Batchable {
1108
+ * getBatchContext = BatchableMixin.prototype.getBatchContext.bind(this);
1109
+ * createWorkerOutcome = BatchableMixin.prototype.createWorkerOutcome.bind(this);
1110
+ * batchWorkerSuccess = BatchableMixin.prototype.batchWorkerSuccess.bind(this);
1111
+ * // ... other required Batchable methods
1112
+ *
1113
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1114
+ * const batchCtx = this.getBatchContext(context);
1115
+ * if (!batchCtx) {
1116
+ * return this.failure('No batch context found');
1117
+ * }
1118
+ *
1119
+ * const results = [];
1120
+ * for (let i = batchCtx.startCursor; i < batchCtx.endCursor; i++) {
1121
+ * results.push(await this.processItem(i));
1122
+ * }
1123
+ *
1124
+ * const outcome = this.createWorkerOutcome(results.length, results.length);
1125
+ * return this.batchWorkerSuccess(outcome);
1126
+ * }
1127
+ * }
1128
+ * ```
1129
+ */
1130
+ declare class BatchableMixin implements Batchable {
1131
+ /**
1132
+ * Create a cursor configuration for a batch range.
1133
+ *
1134
+ * @param start - Starting cursor position (inclusive)
1135
+ * @param end - Ending cursor position (exclusive)
1136
+ * @param stepSize - Step size for iteration (default: 1)
1137
+ * @param metadata - Additional metadata for this cursor range
1138
+ * @returns CursorConfig for the specified range
1139
+ */
1140
+ createCursorConfig(start: number, end: number, stepSize?: number, metadata?: Record<string, unknown>): CursorConfig;
1141
+ /**
1142
+ * Create cursor ranges for batch processing.
1143
+ *
1144
+ * Divides totalItems into batches of batchSize, optionally limiting
1145
+ * the number of batches.
1146
+ *
1147
+ * @param totalItems - Total number of items to process
1148
+ * @param batchSize - Number of items per batch
1149
+ * @param stepSize - Step size for iteration (default: 1)
1150
+ * @param maxBatches - Maximum number of batches (optional)
1151
+ * @returns Array of CursorConfig for each batch
1152
+ */
1153
+ createCursorRanges(totalItems: number, batchSize: number, stepSize?: number, maxBatches?: number): CursorConfig[];
1154
+ /**
1155
+ * Create cursor configurations for a specific number of workers.
1156
+ *
1157
+ * Ruby-style method that divides items into worker_count roughly equal ranges.
1158
+ * Uses ceiling division to ensure all items are covered.
1159
+ *
1160
+ * ## Cursor Boundary Math
1161
+ *
1162
+ * 1. items_per_worker = ceil(total_items / worker_count)
1163
+ * 2. For worker i (0-indexed):
1164
+ * - start = i * items_per_worker
1165
+ * - end = min((i + 1) * items_per_worker, total_items)
1166
+ * - batch_size = end - start
1167
+ *
1168
+ * Example: 1000 items, 3 workers
1169
+ * - items_per_worker = ceil(1000/3) = 334
1170
+ * - Worker 0: start=0, end=334, size=334
1171
+ * - Worker 1: start=334, end=668, size=334
1172
+ * - Worker 2: start=668, end=1000, size=332
1173
+ *
1174
+ * Cross-language standard: matches Ruby's create_cursor_configs(total_items, worker_count).
1175
+ *
1176
+ * @param totalItems - Total number of items to process
1177
+ * @param workerCount - Number of workers to create configs for (must be > 0)
1178
+ * @returns Array of BatchWorkerConfig for each worker
1179
+ */
1180
+ createCursorConfigs(totalItems: number, workerCount: number): BatchWorkerConfig[];
1181
+ /**
1182
+ * Create a batch analyzer outcome.
1183
+ *
1184
+ * Convenience method that creates cursor ranges and wraps them
1185
+ * in a BatchAnalyzerOutcome.
1186
+ *
1187
+ * @param totalItems - Total number of items to process
1188
+ * @param batchSize - Number of items per batch
1189
+ * @param stepSize - Step size for iteration (default: 1)
1190
+ * @param batchMetadata - Metadata to pass to all batch workers
1191
+ * @returns BatchAnalyzerOutcome ready for batchAnalyzerSuccess
1192
+ */
1193
+ createBatchOutcome(totalItems: number, batchSize: number, stepSize?: number, batchMetadata?: Record<string, unknown>): BatchAnalyzerOutcome;
1194
+ /**
1195
+ * Create a batch worker outcome.
1196
+ *
1197
+ * @param itemsProcessed - Total items processed in this batch
1198
+ * @param itemsSucceeded - Items that succeeded (default: itemsProcessed)
1199
+ * @param itemsFailed - Items that failed (default: 0)
1200
+ * @param itemsSkipped - Items that were skipped (default: 0)
1201
+ * @param results - Individual item results
1202
+ * @param errors - Individual item errors
1203
+ * @param lastCursor - Last cursor position processed
1204
+ * @param batchMetadata - Additional batch metadata
1205
+ * @returns BatchWorkerOutcome ready for batchWorkerSuccess
1206
+ */
1207
+ createWorkerOutcome(itemsProcessed: number, itemsSucceeded?: number, itemsFailed?: number, itemsSkipped?: number, results?: Array<Record<string, unknown>>, errors?: Array<Record<string, unknown>>, lastCursor?: number | null, batchMetadata?: Record<string, unknown>): BatchWorkerOutcome;
1208
+ /**
1209
+ * Get the batch context from a step context.
1210
+ *
1211
+ * Looks for batch context in step_config, input_data, or step_inputs.
1212
+ *
1213
+ * @param context - The step context
1214
+ * @returns BatchWorkerContext or null if not found
1215
+ */
1216
+ getBatchContext(context: StepContext): BatchWorkerContext | null;
1217
+ /**
1218
+ * Get Rust batch worker inputs from step context.
1219
+ *
1220
+ * Returns the BatchWorkerInputs structure from workflow_step.inputs,
1221
+ * which contains cursor config, batch metadata, and no-op flag.
1222
+ *
1223
+ * Cross-language standard: matches Ruby's get_batch_context pattern
1224
+ * for accessing Rust-provided batch configuration.
1225
+ *
1226
+ * @param context - The step context
1227
+ * @returns BatchWorkerInputs or null if not found
1228
+ */
1229
+ getBatchWorkerInputs(context: StepContext): Partial<RustBatchWorkerInputs> | null;
1230
+ /**
1231
+ * Handle no-op placeholder worker scenario.
1232
+ *
1233
+ * Returns a success result if the worker is a no-op placeholder
1234
+ * (created when a batchable step returns NoBatches), otherwise
1235
+ * returns null to allow normal processing to continue.
1236
+ *
1237
+ * Cross-language standard: matches Ruby's handle_no_op_worker.
1238
+ *
1239
+ * @param context - The step context
1240
+ * @returns Success result if no-op, null otherwise
1241
+ *
1242
+ * @example
1243
+ * ```typescript
1244
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1245
+ * const noOpResult = this.handleNoOpWorker(context);
1246
+ * if (noOpResult) {
1247
+ * return noOpResult;
1248
+ * }
1249
+ * // ... normal processing
1250
+ * }
1251
+ * ```
1252
+ */
1253
+ handleNoOpWorker(context: StepContext): StepHandlerResult | null;
1254
+ /**
1255
+ * Create a success result for a batch analyzer.
1256
+ *
1257
+ * Formats the BatchAnalyzerOutcome in the structure expected by
1258
+ * the orchestration layer.
1259
+ *
1260
+ * @param outcome - The batch analyzer outcome
1261
+ * @param metadata - Optional additional metadata
1262
+ * @returns A success StepHandlerResult with the batch outcome
1263
+ */
1264
+ batchAnalyzerSuccess(outcome: BatchAnalyzerOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1265
+ /**
1266
+ * Create a success result for a batch worker.
1267
+ *
1268
+ * Formats the BatchWorkerOutcome in the structure expected by
1269
+ * the orchestration layer.
1270
+ *
1271
+ * @param outcome - The batch worker outcome
1272
+ * @param metadata - Optional additional metadata
1273
+ * @returns A success StepHandlerResult with the worker outcome
1274
+ */
1275
+ batchWorkerSuccess(outcome: BatchWorkerOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1276
+ /**
1277
+ * TAS-125: Yield checkpoint for batch processing.
1278
+ *
1279
+ * Use this method when your handler needs to persist progress and be
1280
+ * re-dispatched for continued processing. This is useful for:
1281
+ * - Processing very large datasets that exceed memory limits
1282
+ * - Providing progress visibility for long-running batch jobs
1283
+ * - Enabling graceful shutdown with resumption capability
1284
+ *
1285
+ * Unlike batchWorkerSuccess, this does NOT complete the step.
1286
+ * Instead, it persists the checkpoint and causes the step to be
1287
+ * re-dispatched with the updated checkpoint context.
1288
+ *
1289
+ * @param cursor - Position to resume from
1290
+ * - number: For offset-based pagination (row number)
1291
+ * - string: For cursor-based pagination (opaque token)
1292
+ * - object: For complex cursors (e.g., {page_token: "..."})
1293
+ * @param itemsProcessed - Total items processed so far (cumulative across all yields)
1294
+ * @param accumulatedResults - Partial aggregations to carry forward
1295
+ * @returns A StepHandlerResult with checkpoint_yield type
1296
+ *
1297
+ * @example
1298
+ * ```typescript
1299
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1300
+ * const batchCtx = this.getBatchContext(context);
1301
+ * const start = batchCtx?.checkpointCursor ?? batchCtx?.startCursor ?? 0;
1302
+ * const accumulated = batchCtx?.accumulatedResults ?? { total: 0 };
1303
+ *
1304
+ * // Process a chunk
1305
+ * const chunkSize = 1000;
1306
+ * for (let i = 0; i < chunkSize && start + i < batchCtx.endCursor; i++) {
1307
+ * accumulated.total += await processItem(start + i);
1308
+ * }
1309
+ *
1310
+ * const newCursor = start + chunkSize;
1311
+ * if (newCursor < batchCtx.endCursor) {
1312
+ * // More work to do - yield checkpoint
1313
+ * return this.checkpointYield(newCursor, newCursor, accumulated);
1314
+ * }
1315
+ *
1316
+ * // Done - return final success
1317
+ * return this.batchWorkerSuccess(
1318
+ * this.createWorkerOutcome(batchCtx.endCursor - batchCtx.startCursor)
1319
+ * );
1320
+ * }
1321
+ * ```
1322
+ */
1323
+ checkpointYield(cursor: number | string | Record<string, unknown>, itemsProcessed: number, accumulatedResults?: Record<string, unknown>): StepHandlerResult;
1324
+ /**
1325
+ * Detect batch aggregation scenario from dependency results.
1326
+ *
1327
+ * Cross-language standard: matches Ruby's detect_aggregation_scenario,
1328
+ * Python's detect_aggregation_scenario, and Rust's BatchAggregationScenario::detect.
1329
+ *
1330
+ * @param dependencyResults - All dependency results from the step context.
1331
+ * @param batchableStepName - Name of the batchable step (e.g., "analyze_csv").
1332
+ * @param batchWorkerPrefix - Prefix for batch worker step names (e.g., "process_csv_batch_").
1333
+ * @returns BatchAggregationScenario indicating NoBatches or WithBatches.
1334
+ *
1335
+ * @example
1336
+ * ```typescript
1337
+ * const scenario = this.detectAggregationScenario(
1338
+ * context.dependencyResults,
1339
+ * 'analyze_csv',
1340
+ * 'process_csv_batch_'
1341
+ * );
1342
+ * if (scenario.isNoBatches) {
1343
+ * return this.noBatchesAggregationResult({ total: 0 });
1344
+ * }
1345
+ * ```
1346
+ */
1347
+ detectAggregationScenario(dependencyResults: Record<string, unknown>, batchableStepName: string, batchWorkerPrefix: string): BatchAggregationScenario;
1348
+ /**
1349
+ * Create a success result for NoBatches aggregation scenario.
1350
+ *
1351
+ * Cross-language standard: matches Ruby's no_batches_aggregation_result
1352
+ * and Python's no_batches_aggregation_result.
1353
+ *
1354
+ * @param zeroMetrics - Metrics to return (typically zeros).
1355
+ * @returns Success result with workerCount=0 and scenario="no_batches".
1356
+ *
1357
+ * @example
1358
+ * ```typescript
1359
+ * return this.noBatchesAggregationResult({
1360
+ * totalProcessed: 0,
1361
+ * totalValue: 0.0,
1362
+ * });
1363
+ * ```
1364
+ */
1365
+ noBatchesAggregationResult(zeroMetrics?: Record<string, unknown>): StepHandlerResult;
1366
+ /**
1367
+ * Aggregate batch worker results handling both scenarios.
1368
+ *
1369
+ * Cross-language standard: matches Ruby's aggregate_batch_worker_results
1370
+ * and Python's aggregate_batch_worker_results.
1371
+ * Handles both NoBatches and WithBatches scenarios automatically.
1372
+ *
1373
+ * For NoBatches, returns zeroMetrics with worker_count=0.
1374
+ * For WithBatches, calls aggregationFn with batchResults dict.
1375
+ *
1376
+ * @param scenario - BatchAggregationScenario from detectAggregationScenario().
1377
+ * @param zeroMetrics - Metrics to return for NoBatches scenario.
1378
+ * @param aggregationFn - Function to aggregate batch results. Receives dict of
1379
+ * worker_name -> result_dict, returns aggregated metrics dict.
1380
+ * @returns Success result with aggregated data and worker_count.
1381
+ *
1382
+ * @example
1383
+ * ```typescript
1384
+ * const scenario = this.detectAggregationScenario(
1385
+ * context.dependencyResults,
1386
+ * 'analyze_csv',
1387
+ * 'process_csv_batch_'
1388
+ * );
1389
+ *
1390
+ * return this.aggregateBatchWorkerResults(
1391
+ * scenario,
1392
+ * { totalProcessed: 0 },
1393
+ * (batchResults) => {
1394
+ * let total = 0;
1395
+ * for (const result of Object.values(batchResults)) {
1396
+ * total += (result.count as number) || 0;
1397
+ * }
1398
+ * return { totalProcessed: total };
1399
+ * }
1400
+ * );
1401
+ * ```
1402
+ */
1403
+ aggregateBatchWorkerResults(scenario: BatchAggregationScenario, zeroMetrics?: Record<string, unknown>, aggregationFn?: (batchResults: Record<string, Record<string, unknown>>) => Record<string, unknown>): StepHandlerResult;
1404
+ /**
1405
+ * Aggregate results from multiple batch workers.
1406
+ *
1407
+ * Delegates to `aggregateBatchResults` from types/batch.ts (TAS-112/TAS-123).
1408
+ * Cross-language standard: matches Python's aggregate_batch_results.
1409
+ *
1410
+ * @param workerResults - Array of results from batch worker steps
1411
+ * @param maxErrors - Maximum number of errors to collect (default: 100)
1412
+ * @returns Aggregated summary of all batch processing
1413
+ *
1414
+ * @example
1415
+ * ```typescript
1416
+ * // In an aggregator handler
1417
+ * const workerResults = context.getAllDependencyResults('process_batch_');
1418
+ * const summary = BatchableMixin.aggregateWorkerResults(workerResults);
1419
+ * return this.success(summary);
1420
+ * ```
1421
+ */
1422
+ static aggregateWorkerResults(workerResults: Array<Record<string, unknown> | null>, maxErrors?: number): BatchAggregationResult;
1423
+ }
1424
+ /**
1425
+ * Helper function to apply Batchable methods to a handler class.
1426
+ *
1427
+ * This is a convenience for applying all Batchable methods at once.
1428
+ *
1429
+ * @example
1430
+ * ```typescript
1431
+ * class MyBatchHandler extends StepHandler {
1432
+ * constructor() {
1433
+ * super();
1434
+ * applyBatchable(this);
1435
+ * }
1436
+ * }
1437
+ * ```
1438
+ */
1439
+ declare function applyBatchable<T extends object>(target: T): T & Batchable;
1440
+
1441
+ /**
1442
+ * Decision mixin for workflow routing.
1443
+ *
1444
+ * TAS-112: Composition Pattern - Decision Mixin
1445
+ *
1446
+ * This module provides the DecisionMixin class for step handlers that make
1447
+ * routing decisions. Use via interface implementation with method binding.
1448
+ *
1449
+ * @example
1450
+ * ```typescript
1451
+ * class RouteOrderHandler extends StepHandler implements DecisionCapable {
1452
+ * static handlerName = 'route_order';
1453
+ *
1454
+ * // Bind DecisionMixin methods
1455
+ * decisionSuccess = DecisionMixin.prototype.decisionSuccess.bind(this);
1456
+ * skipBranches = DecisionMixin.prototype.skipBranches.bind(this);
1457
+ * // ... other required methods
1458
+ *
1459
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1460
+ * const orderType = context.inputData['order_type'];
1461
+ * if (orderType === 'premium') {
1462
+ * return this.decisionSuccess(
1463
+ * ['validate_premium', 'process_premium'],
1464
+ * { order_type: orderType }
1465
+ * );
1466
+ * }
1467
+ * return this.decisionSuccess(['process_standard']);
1468
+ * }
1469
+ * }
1470
+ * ```
1471
+ *
1472
+ * @module handler/mixins/decision
1473
+ */
1474
+
1475
+ /**
1476
+ * Type of decision point outcome.
1477
+ */
1478
+ declare enum DecisionType {
1479
+ CREATE_STEPS = "create_steps",
1480
+ NO_BRANCHES = "no_branches"
1481
+ }
1482
+ /**
1483
+ * Outcome from a decision point handler.
1484
+ *
1485
+ * Decision handlers return this to indicate which branch(es) of a workflow
1486
+ * to execute.
1487
+ */
1488
+ interface DecisionPointOutcome {
1489
+ /** Type of decision made */
1490
+ decisionType: DecisionType;
1491
+ /** Names of steps to execute next */
1492
+ nextStepNames: string[];
1493
+ /** Optional dynamically created steps */
1494
+ dynamicSteps?: Array<Record<string, unknown>>;
1495
+ /** Human-readable reason for the decision */
1496
+ reason?: string;
1497
+ /** Context data for routing */
1498
+ routingContext: Record<string, unknown>;
1499
+ }
1500
+ /**
1501
+ * Interface for decision-capable handlers.
1502
+ *
1503
+ * Implement this interface and bind DecisionMixin methods to get decision functionality.
1504
+ */
1505
+ interface DecisionCapable {
1506
+ /** Handler name (from StepHandler) */
1507
+ name: string;
1508
+ /** Handler version (from StepHandler) */
1509
+ version: string;
1510
+ decisionSuccess(steps: string[], routingContext?: Record<string, unknown>, metadata?: Record<string, unknown>): StepHandlerResult;
1511
+ decisionSuccessWithOutcome(outcome: DecisionPointOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1512
+ decisionNoBranches(outcome: DecisionPointOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1513
+ skipBranches(reason: string, routingContext?: Record<string, unknown>, metadata?: Record<string, unknown>): StepHandlerResult;
1514
+ decisionFailure(message: string, errorType?: string, retryable?: boolean, metadata?: Record<string, unknown>): StepHandlerResult;
1515
+ }
1516
+ /**
1517
+ * Implementation of decision methods.
1518
+ *
1519
+ * TAS-112: Use via interface implementation with method binding.
1520
+ *
1521
+ * Decision handlers are used to make routing decisions in workflows.
1522
+ * They evaluate conditions and determine which steps should execute next.
1523
+ */
1524
+ declare class DecisionMixin implements DecisionCapable {
1525
+ get name(): string;
1526
+ get version(): string;
1527
+ /**
1528
+ * Simplified decision success helper (cross-language standard API).
1529
+ *
1530
+ * Use this when routing to one or more steps based on a decision.
1531
+ * This is the recommended method for most decision handlers.
1532
+ *
1533
+ * @param steps - List of step names to activate
1534
+ * @param routingContext - Optional context for routing decisions
1535
+ * @param metadata - Optional additional metadata
1536
+ * @returns A success StepHandlerResult with the decision outcome
1537
+ */
1538
+ decisionSuccess(steps: string[], routingContext?: Record<string, unknown>, metadata?: Record<string, unknown>): StepHandlerResult;
1539
+ /**
1540
+ * Create a success result with a DecisionPointOutcome.
1541
+ *
1542
+ * Use this for complex decision outcomes that require dynamic steps
1543
+ * or advanced routing. For simple step routing, use `decisionSuccess()`.
1544
+ */
1545
+ decisionSuccessWithOutcome(outcome: DecisionPointOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1546
+ /**
1547
+ * Create a success result for a decision with no branches.
1548
+ *
1549
+ * Use this when the decision results in no additional steps being executed.
1550
+ * This is still a successful outcome - the decision was made correctly,
1551
+ * it just doesn't require any follow-up steps.
1552
+ */
1553
+ decisionNoBranches(outcome: DecisionPointOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1554
+ /**
1555
+ * Convenience method to skip all branches.
1556
+ *
1557
+ * @param reason - Human-readable reason for skipping branches
1558
+ * @param routingContext - Optional context data
1559
+ * @param metadata - Optional additional metadata
1560
+ * @returns A success StepHandlerResult indicating no branches
1561
+ */
1562
+ skipBranches(reason: string, routingContext?: Record<string, unknown>, metadata?: Record<string, unknown>): StepHandlerResult;
1563
+ /**
1564
+ * Create a failure result for a decision that could not be made.
1565
+ *
1566
+ * Use this when the handler cannot determine the appropriate routing,
1567
+ * typically due to invalid input data or missing required information.
1568
+ *
1569
+ * Decision failures are usually NOT retryable.
1570
+ */
1571
+ decisionFailure(message: string, errorType?: string, retryable?: boolean, metadata?: Record<string, unknown>): StepHandlerResult;
1572
+ }
1573
+ /**
1574
+ * Helper function to apply decision methods to a handler instance.
1575
+ *
1576
+ * @example
1577
+ * ```typescript
1578
+ * class MyDecisionHandler extends StepHandler {
1579
+ * constructor() {
1580
+ * super();
1581
+ * applyDecision(this);
1582
+ * }
1583
+ * }
1584
+ * ```
1585
+ */
1586
+ declare function applyDecision<T extends {
1587
+ name: string;
1588
+ version: string;
1589
+ }>(target: T): T & DecisionCapable;
1590
+
1591
+ /**
1592
+ * Decision handler for workflow routing.
1593
+ *
1594
+ * TAS-112: Composition Pattern (DEPRECATED CLASS)
1595
+ *
1596
+ * This module provides the DecisionHandler class for backward compatibility.
1597
+ * For new code, use the mixin pattern:
1598
+ *
1599
+ * @example Using DecisionMixin
1600
+ * ```typescript
1601
+ * import { StepHandler } from './base';
1602
+ * import { DecisionMixin, DecisionCapable, applyDecision } from './mixins/decision';
1603
+ *
1604
+ * class RouteOrderHandler extends StepHandler implements DecisionCapable {
1605
+ * static handlerName = 'route_order';
1606
+ *
1607
+ * constructor() {
1608
+ * super();
1609
+ * applyDecision(this);
1610
+ * }
1611
+ *
1612
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1613
+ * const orderType = context.inputData['order_type'];
1614
+ * if (orderType === 'premium') {
1615
+ * return this.decisionSuccess(
1616
+ * ['validate_premium', 'process_premium'],
1617
+ * { order_type: orderType }
1618
+ * );
1619
+ * }
1620
+ * return this.decisionSuccess(['process_standard']);
1621
+ * }
1622
+ * }
1623
+ * ```
1624
+ *
1625
+ * @module handler/decision
1626
+ */
1627
+
1628
+ /**
1629
+ * Base class for decision point step handlers.
1630
+ *
1631
+ * TAS-112: This class is provided for backward compatibility.
1632
+ * For new code, prefer using DecisionMixin directly with applyDecision().
1633
+ *
1634
+ * Decision handlers are used to make routing decisions in workflows.
1635
+ * They evaluate conditions and determine which steps should execute next.
1636
+ *
1637
+ * @example
1638
+ * ```typescript
1639
+ * class CustomerTierRouter extends DecisionHandler {
1640
+ * static handlerName = 'route_by_tier';
1641
+ *
1642
+ * async call(context: StepContext): Promise<StepHandlerResult> {
1643
+ * const tier = context.inputData['customer_tier'];
1644
+ * if (tier === 'enterprise') {
1645
+ * return this.decisionSuccess(
1646
+ * ['enterprise_validation', 'enterprise_processing'],
1647
+ * { tier }
1648
+ * );
1649
+ * } else if (tier === 'premium') {
1650
+ * return this.decisionSuccess(['premium_processing']);
1651
+ * } else {
1652
+ * return this.decisionSuccess(['standard_processing']);
1653
+ * }
1654
+ * }
1655
+ * }
1656
+ * ```
1657
+ */
1658
+ declare abstract class DecisionHandler extends StepHandler {
1659
+ private readonly _decisionMixin;
1660
+ get capabilities(): string[];
1661
+ /**
1662
+ * Simplified decision success helper (cross-language standard API).
1663
+ *
1664
+ * Use this when routing to one or more steps based on a decision.
1665
+ * This is the recommended method for most decision handlers.
1666
+ */
1667
+ protected decisionSuccess(steps: string[], routingContext?: Record<string, unknown>, metadata?: Record<string, unknown>): StepHandlerResult;
1668
+ /**
1669
+ * Create a success result with a DecisionPointOutcome.
1670
+ *
1671
+ * Use this for complex decision outcomes that require dynamic steps
1672
+ * or advanced routing. For simple step routing, use `decisionSuccess()`.
1673
+ */
1674
+ protected decisionSuccessWithOutcome(outcome: DecisionPointOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1675
+ /**
1676
+ * Create a success result for a decision with no branches.
1677
+ *
1678
+ * Use this when the decision results in no additional steps being executed.
1679
+ */
1680
+ protected decisionNoBranches(outcome: DecisionPointOutcome, metadata?: Record<string, unknown>): StepHandlerResult;
1681
+ /**
1682
+ * Convenience method to skip all branches.
1683
+ */
1684
+ protected skipBranches(reason: string, routingContext?: Record<string, unknown>, metadata?: Record<string, unknown>): StepHandlerResult;
1685
+ /**
1686
+ * Create a failure result for a decision that could not be made.
1687
+ */
1688
+ protected decisionFailure(message: string, errorType?: string, retryable?: boolean, metadata?: Record<string, unknown>): StepHandlerResult;
1689
+ }
1690
+
1691
+ /**
1692
+ * Domain Events Module for TypeScript Workers
1693
+ *
1694
+ * Provides infrastructure for custom domain event publishers and subscribers.
1695
+ * Publishers transform step results into business events; subscribers handle
1696
+ * fast (in-process) events for internal processing.
1697
+ *
1698
+ * Architecture: Handlers DON'T publish events directly. Events are declared
1699
+ * in YAML templates, and Rust orchestration publishes them after step completion.
1700
+ * Custom publishers only transform payloads. Subscribers only receive fast events.
1701
+ *
1702
+ * @module handler/domain-events
1703
+ * @see docs/architecture/domain-events.md
1704
+ * @see TAS-122, TAS-112 Phase 7
1705
+ */
1706
+
1707
+ /**
1708
+ * Context passed to publishers for event transformation.
1709
+ *
1710
+ * Contains all information needed to build a business event payload.
1711
+ */
1712
+ interface StepEventContext {
1713
+ /** UUID of the task */
1714
+ readonly taskUuid: string;
1715
+ /** UUID of the step */
1716
+ readonly stepUuid: string;
1717
+ /** Name of the step handler */
1718
+ readonly stepName: string;
1719
+ /** Namespace (e.g., "payments", "inventory") */
1720
+ readonly namespace: string;
1721
+ /** Correlation ID for distributed tracing */
1722
+ readonly correlationId: string;
1723
+ /** Step result data (success payload or error info) */
1724
+ readonly result?: Record<string, unknown>;
1725
+ /** Execution metadata */
1726
+ readonly metadata: Record<string, unknown>;
1727
+ }
1728
+ /**
1729
+ * Event declaration from YAML task template.
1730
+ */
1731
+ interface EventDeclaration {
1732
+ /** Event name (e.g., "payment.processed") */
1733
+ readonly name: string;
1734
+ /** Publication condition: "success" | "failure" | "always" */
1735
+ readonly condition?: 'success' | 'failure' | 'retryable_failure' | 'permanent_failure' | 'always';
1736
+ /** Delivery mode: "durable" (PGMQ) | "fast" (in-process) | "broadcast" (both) */
1737
+ readonly deliveryMode?: 'durable' | 'fast' | 'broadcast';
1738
+ /** Custom publisher name (optional) */
1739
+ readonly publisher?: string;
1740
+ /** JSON schema for payload validation (optional) */
1741
+ readonly schema?: Record<string, unknown>;
1742
+ }
1743
+ /**
1744
+ * Step result passed to publishers.
1745
+ */
1746
+ interface StepResult {
1747
+ /** Whether the step succeeded */
1748
+ readonly success: boolean;
1749
+ /** Step handler's return value */
1750
+ readonly result?: Record<string, unknown>;
1751
+ /** Execution metadata */
1752
+ readonly metadata?: Record<string, unknown>;
1753
+ }
1754
+ /**
1755
+ * Domain event structure for subscribers.
1756
+ *
1757
+ * This is the shape of events received by BaseSubscriber.handle().
1758
+ */
1759
+ interface DomainEvent {
1760
+ /** Unique event ID (UUID v7) */
1761
+ readonly eventId: string;
1762
+ /** Event name (e.g., "payment.processed") */
1763
+ readonly eventName: string;
1764
+ /** Business payload from publisher transformation */
1765
+ readonly payload: Record<string, unknown>;
1766
+ /** Event metadata */
1767
+ readonly metadata: DomainEventMetadata;
1768
+ /** Original step execution result */
1769
+ readonly executionResult: StepResult;
1770
+ }
1771
+ /**
1772
+ * Metadata attached to every domain event.
1773
+ */
1774
+ interface DomainEventMetadata {
1775
+ /** Task UUID */
1776
+ readonly taskUuid: string;
1777
+ /** Step UUID */
1778
+ readonly stepUuid: string;
1779
+ /** Step name */
1780
+ readonly stepName?: string;
1781
+ /** Namespace */
1782
+ readonly namespace: string;
1783
+ /** Correlation ID for tracing */
1784
+ readonly correlationId: string;
1785
+ /** When the event was fired (ISO8601) */
1786
+ readonly firedAt: string;
1787
+ /** Publisher that created this event */
1788
+ readonly publisher?: string;
1789
+ /** Additional custom metadata */
1790
+ readonly [key: string]: unknown;
1791
+ }
1792
+ /**
1793
+ * Context passed to the publish() method.
1794
+ *
1795
+ * Cross-language standard API (TAS-96).
1796
+ */
1797
+ interface PublishContext {
1798
+ /** Event name */
1799
+ readonly eventName: string;
1800
+ /** Step result */
1801
+ readonly stepResult: StepResult;
1802
+ /** Event declaration from YAML */
1803
+ readonly eventDeclaration?: EventDeclaration;
1804
+ /** Step execution context */
1805
+ readonly stepContext?: StepEventContext;
1806
+ }
1807
+ /**
1808
+ * Abstract base class for custom domain event publishers.
1809
+ *
1810
+ * Publishers transform step execution results into business events.
1811
+ * They are declared in YAML via the `publisher:` field and registered
1812
+ * at bootstrap time.
1813
+ *
1814
+ * NOTE: Publishers don't call publish APIs directly. They transform data
1815
+ * that Rust orchestration publishes.
1816
+ *
1817
+ * @example
1818
+ * ```typescript
1819
+ * class PaymentEventPublisher extends BasePublisher {
1820
+ * readonly publisherName = 'PaymentEventPublisher';
1821
+ *
1822
+ * transformPayload(stepResult: StepResult, eventDecl?: EventDeclaration): Record<string, unknown> {
1823
+ * const result = stepResult.result ?? {};
1824
+ * return {
1825
+ * transactionId: result.transaction_id,
1826
+ * amount: result.amount,
1827
+ * currency: result.currency ?? 'USD',
1828
+ * status: stepResult.success ? 'succeeded' : 'failed',
1829
+ * };
1830
+ * }
1831
+ *
1832
+ * shouldPublish(stepResult: StepResult): boolean {
1833
+ * return stepResult.success && stepResult.result?.transaction_id != null;
1834
+ * }
1835
+ * }
1836
+ * ```
1837
+ */
1838
+ declare abstract class BasePublisher {
1839
+ protected readonly logger: Logger;
1840
+ /**
1841
+ * Publisher name for registry lookup.
1842
+ * Must match the `publisher:` field in YAML.
1843
+ */
1844
+ abstract readonly publisherName: string;
1845
+ /**
1846
+ * Transform step result into business event payload.
1847
+ *
1848
+ * Override to customize the event payload for your domain.
1849
+ * Default returns the step result as-is.
1850
+ *
1851
+ * @param stepResult - The step execution result
1852
+ * @param eventDeclaration - The event declaration from YAML
1853
+ * @param stepContext - The step execution context
1854
+ * @returns Business event payload to publish
1855
+ */
1856
+ transformPayload(stepResult: StepResult, _eventDeclaration?: EventDeclaration, _stepContext?: StepEventContext): Record<string, unknown>;
1857
+ /**
1858
+ * Determine if this event should be published.
1859
+ *
1860
+ * Override to add custom conditions beyond YAML's `condition:` field.
1861
+ * The YAML condition is evaluated first by Rust orchestration.
1862
+ *
1863
+ * @param stepResult - The step execution result
1864
+ * @param eventDeclaration - The event declaration from YAML
1865
+ * @param stepContext - The step execution context
1866
+ * @returns true if the event should be published
1867
+ */
1868
+ shouldPublish(_stepResult: StepResult, _eventDeclaration?: EventDeclaration, _stepContext?: StepEventContext): boolean;
1869
+ /**
1870
+ * Add additional metadata to the event.
1871
+ *
1872
+ * Override to add custom metadata fields.
1873
+ *
1874
+ * @param stepResult - The step execution result
1875
+ * @param eventDeclaration - The event declaration from YAML
1876
+ * @param stepContext - The step execution context
1877
+ * @returns Additional metadata to merge into event metadata
1878
+ */
1879
+ additionalMetadata(_stepResult: StepResult, _eventDeclaration?: EventDeclaration, _stepContext?: StepEventContext): Record<string, unknown>;
1880
+ /**
1881
+ * Hook called before publishing.
1882
+ *
1883
+ * Override for pre-publish validation, logging, or metrics.
1884
+ * Return false to prevent publishing.
1885
+ *
1886
+ * @param eventName - The event name
1887
+ * @param payload - The transformed payload
1888
+ * @param metadata - The event metadata
1889
+ * @returns true to continue, false to skip publishing
1890
+ */
1891
+ beforePublish(eventName: string, _payload: Record<string, unknown>, _metadata: Record<string, unknown>): boolean;
1892
+ /**
1893
+ * Hook called after successful publishing.
1894
+ *
1895
+ * Override for post-publish logging, metrics, or cleanup.
1896
+ *
1897
+ * @param eventName - The event name
1898
+ * @param payload - The transformed payload
1899
+ * @param metadata - The event metadata
1900
+ */
1901
+ afterPublish(eventName: string, _payload: Record<string, unknown>, _metadata: Record<string, unknown>): void;
1902
+ /**
1903
+ * Hook called if publishing fails.
1904
+ *
1905
+ * Override for error handling, logging, or fallback behavior.
1906
+ *
1907
+ * @param eventName - The event name
1908
+ * @param error - The error that occurred
1909
+ * @param payload - The transformed payload
1910
+ */
1911
+ onPublishError(eventName: string, error: Error, _payload: Record<string, unknown>): void;
1912
+ /**
1913
+ * Cross-language standard: Publish an event with unified context.
1914
+ *
1915
+ * Coordinates the lifecycle hooks into a single publish call.
1916
+ *
1917
+ * @param ctx - Publish context containing all required data
1918
+ * @returns true if event was published, false if skipped
1919
+ */
1920
+ publish(ctx: PublishContext): boolean;
1921
+ }
1922
+ /**
1923
+ * Default publisher that passes step result through unchanged.
1924
+ */
1925
+ declare class DefaultPublisher extends BasePublisher {
1926
+ readonly publisherName = "default";
1927
+ transformPayload(stepResult: StepResult): Record<string, unknown>;
1928
+ }
1929
+ /**
1930
+ * Static interface for subscriber classes (for type checking).
1931
+ */
1932
+ interface SubscriberClass {
1933
+ /** Patterns to subscribe to */
1934
+ subscribesTo(): string[];
1935
+ /** Constructor */
1936
+ new (): BaseSubscriber;
1937
+ }
1938
+ /**
1939
+ * Abstract base class for domain event subscribers.
1940
+ *
1941
+ * Subscribers handle fast (in-process) domain events for internal processing.
1942
+ * They subscribe to event patterns and receive events via the InProcessEventBus.
1943
+ *
1944
+ * @example
1945
+ * ```typescript
1946
+ * class MetricsSubscriber extends BaseSubscriber {
1947
+ * static subscribesTo(): string[] {
1948
+ * return ['*']; // All events
1949
+ * }
1950
+ *
1951
+ * handle(event: DomainEvent): void {
1952
+ * metrics.increment(`domain_events.${event.eventName.replace('.', '_')}`);
1953
+ * }
1954
+ * }
1955
+ *
1956
+ * class PaymentSubscriber extends BaseSubscriber {
1957
+ * static subscribesTo(): string[] {
1958
+ * return ['payment.*']; // Only payment events
1959
+ * }
1960
+ *
1961
+ * handle(event: DomainEvent): void {
1962
+ * if (event.eventName === 'payment.processed') {
1963
+ * notifyAccounting(event.payload);
1964
+ * }
1965
+ * }
1966
+ * }
1967
+ * ```
1968
+ */
1969
+ declare abstract class BaseSubscriber {
1970
+ protected readonly logger: Logger;
1971
+ private _active;
1972
+ private _subscriptions;
1973
+ /**
1974
+ * Event patterns to subscribe to.
1975
+ *
1976
+ * Override this static method to declare patterns.
1977
+ * Supports wildcards: "*" matches all, "payment.*" matches payment.processed, etc.
1978
+ *
1979
+ * @returns Array of event patterns
1980
+ */
1981
+ static subscribesTo(): string[];
1982
+ /**
1983
+ * Check if the subscriber is active.
1984
+ */
1985
+ get active(): boolean;
1986
+ /**
1987
+ * Get subscribed patterns.
1988
+ */
1989
+ get subscriptions(): readonly string[];
1990
+ /**
1991
+ * Handle a domain event.
1992
+ *
1993
+ * Subclasses MUST implement this method.
1994
+ *
1995
+ * @param event - The domain event to handle
1996
+ */
1997
+ abstract handle(event: DomainEvent): void | Promise<void>;
1998
+ /**
1999
+ * Hook called before handling an event.
2000
+ *
2001
+ * Override for pre-processing, validation, or filtering.
2002
+ * Return false to skip handling this event.
2003
+ *
2004
+ * @param event - The domain event
2005
+ * @returns true to continue handling, false to skip
2006
+ */
2007
+ beforeHandle(_event: DomainEvent): boolean;
2008
+ /**
2009
+ * Hook called after successful handling.
2010
+ *
2011
+ * Override for post-processing, metrics, or cleanup.
2012
+ *
2013
+ * @param event - The domain event
2014
+ */
2015
+ afterHandle(_event: DomainEvent): void;
2016
+ /**
2017
+ * Hook called if handling fails.
2018
+ *
2019
+ * Override for custom error handling, alerts, or retry logic.
2020
+ * Note: Domain events use fire-and-forget semantics.
2021
+ *
2022
+ * @param event - The domain event
2023
+ * @param error - The error that occurred
2024
+ */
2025
+ onHandleError(event: DomainEvent, error: Error): void;
2026
+ /**
2027
+ * Check if this subscriber matches an event name.
2028
+ *
2029
+ * Supports wildcard patterns:
2030
+ * - "*" matches everything
2031
+ * - "payment.*" matches "payment.processed", "payment.failed"
2032
+ * - "order.created" matches exactly "order.created"
2033
+ *
2034
+ * @param eventName - The event name to check
2035
+ * @returns true if this subscriber should handle the event
2036
+ */
2037
+ matches(eventName: string): boolean;
2038
+ /**
2039
+ * Start listening for events.
2040
+ *
2041
+ * Registers with the InProcessDomainEventPoller.
2042
+ *
2043
+ * @param poller - The event poller to register with
2044
+ */
2045
+ start(poller: InProcessDomainEventPoller): void;
2046
+ /**
2047
+ * Stop listening for events.
2048
+ */
2049
+ stop(): void;
2050
+ /**
2051
+ * Safely handle an event with error capture.
2052
+ */
2053
+ private handleEventSafely;
2054
+ }
2055
+ /**
2056
+ * Error thrown when a required publisher is not registered.
2057
+ */
2058
+ declare class PublisherNotFoundError extends Error {
2059
+ readonly publisherName: string;
2060
+ readonly registeredPublishers: string[];
2061
+ constructor(name: string, registered: string[]);
2062
+ }
2063
+ /**
2064
+ * Error thrown when required publishers are missing during validation.
2065
+ */
2066
+ declare class PublisherValidationError extends Error {
2067
+ readonly missingPublishers: string[];
2068
+ readonly registeredPublishers: string[];
2069
+ constructor(missing: string[], registered: string[]);
2070
+ }
2071
+ /**
2072
+ * Error thrown when modifying a frozen registry.
2073
+ */
2074
+ declare class RegistryFrozenError extends Error {
2075
+ constructor();
2076
+ }
2077
+ /**
2078
+ * Error thrown when registering a duplicate publisher.
2079
+ */
2080
+ declare class DuplicatePublisherError extends Error {
2081
+ readonly publisherName: string;
2082
+ constructor(name: string);
2083
+ }
2084
+ /**
2085
+ * Registry for custom domain event publishers.
2086
+ *
2087
+ * Maps publisher names (from YAML configuration) to their implementations.
2088
+ * Publishers are registered at bootstrap time and validated against task templates.
2089
+ *
2090
+ * @example
2091
+ * ```typescript
2092
+ * const registry = PublisherRegistry.instance;
2093
+ *
2094
+ * // Register custom publishers
2095
+ * registry.register(new PaymentEventPublisher());
2096
+ * registry.register(new InventoryEventPublisher());
2097
+ *
2098
+ * // Validate against templates
2099
+ * registry.validateRequired(['PaymentEventPublisher', 'InventoryEventPublisher']);
2100
+ *
2101
+ * // Look up publishers
2102
+ * const publisher = registry.get('PaymentEventPublisher');
2103
+ * ```
2104
+ */
2105
+ declare class PublisherRegistry {
2106
+ private static _instance;
2107
+ private readonly publishers;
2108
+ private readonly defaultPublisher;
2109
+ private frozen;
2110
+ private readonly logger;
2111
+ private constructor();
2112
+ /**
2113
+ * Get the singleton instance.
2114
+ */
2115
+ static get instance(): PublisherRegistry;
2116
+ /**
2117
+ * Register a custom publisher.
2118
+ *
2119
+ * @param publisher - The publisher instance to register
2120
+ * @throws RegistryFrozenError if registry is frozen
2121
+ * @throws DuplicatePublisherError if name is already registered
2122
+ */
2123
+ register(publisher: BasePublisher): void;
2124
+ /**
2125
+ * Get a publisher by name.
2126
+ *
2127
+ * @param name - The publisher name
2128
+ * @returns The publisher, or undefined if not found
2129
+ */
2130
+ get(name: string): BasePublisher | undefined;
2131
+ /**
2132
+ * Get a publisher by name, or return the default.
2133
+ *
2134
+ * @param name - The publisher name (optional)
2135
+ * @returns The publisher or default
2136
+ */
2137
+ getOrDefault(name?: string): BasePublisher;
2138
+ /**
2139
+ * Get a publisher by name (strict mode).
2140
+ *
2141
+ * @param name - The publisher name
2142
+ * @returns The publisher
2143
+ * @throws PublisherNotFoundError if not registered
2144
+ */
2145
+ getStrict(name: string): BasePublisher;
2146
+ /**
2147
+ * Check if a publisher is registered.
2148
+ */
2149
+ isRegistered(name: string): boolean;
2150
+ /**
2151
+ * Get all registered publisher names.
2152
+ */
2153
+ get registeredNames(): string[];
2154
+ /**
2155
+ * Get count of registered publishers.
2156
+ */
2157
+ get count(): number;
2158
+ /**
2159
+ * Check if registry is empty.
2160
+ */
2161
+ get isEmpty(): boolean;
2162
+ /**
2163
+ * Check if registry is frozen.
2164
+ */
2165
+ get isFrozen(): boolean;
2166
+ /**
2167
+ * Unregister a publisher.
2168
+ *
2169
+ * @throws RegistryFrozenError if registry is frozen
2170
+ */
2171
+ unregister(name: string): boolean;
2172
+ /**
2173
+ * Clear all registered publishers.
2174
+ *
2175
+ * @throws RegistryFrozenError if registry is frozen
2176
+ */
2177
+ clear(): void;
2178
+ /**
2179
+ * Validate that all required publishers are registered.
2180
+ *
2181
+ * After validation, the registry is frozen.
2182
+ *
2183
+ * @param requiredPublishers - Publisher names from YAML configs
2184
+ * @throws PublisherValidationError if some publishers are missing
2185
+ */
2186
+ validateRequired(requiredPublishers: string[]): void;
2187
+ /**
2188
+ * Freeze the registry to prevent further changes.
2189
+ */
2190
+ freeze(): void;
2191
+ /**
2192
+ * Reset the registry (for testing).
2193
+ */
2194
+ reset(): void;
2195
+ }
2196
+ /**
2197
+ * Subscriber statistics.
2198
+ */
2199
+ interface SubscriberStats {
2200
+ /** Whether subscribers have been started */
2201
+ readonly started: boolean;
2202
+ /** Total subscriber count */
2203
+ readonly subscriberCount: number;
2204
+ /** Number of active subscribers */
2205
+ readonly activeCount: number;
2206
+ /** Individual subscriber info */
2207
+ readonly subscribers: ReadonlyArray<{
2208
+ readonly className: string;
2209
+ readonly active: boolean;
2210
+ readonly patterns: readonly string[];
2211
+ }>;
2212
+ }
2213
+ /**
2214
+ * Registry for domain event subscribers.
2215
+ *
2216
+ * Manages the lifecycle of subscribers. Subscribers are registered at bootstrap
2217
+ * time and started/stopped together with the worker.
2218
+ *
2219
+ * @example
2220
+ * ```typescript
2221
+ * const registry = SubscriberRegistry.instance;
2222
+ *
2223
+ * // Register subscriber classes (instantiation deferred)
2224
+ * registry.register(PaymentSubscriber);
2225
+ * registry.register(MetricsSubscriber);
2226
+ *
2227
+ * // Start all subscribers with the poller
2228
+ * registry.startAll(poller);
2229
+ *
2230
+ * // Stop all when shutting down
2231
+ * registry.stopAll();
2232
+ * ```
2233
+ */
2234
+ declare class SubscriberRegistry {
2235
+ private static _instance;
2236
+ private readonly subscriberClasses;
2237
+ private readonly subscribers;
2238
+ private started;
2239
+ private readonly logger;
2240
+ private constructor();
2241
+ /**
2242
+ * Get the singleton instance.
2243
+ */
2244
+ static get instance(): SubscriberRegistry;
2245
+ /**
2246
+ * Register a subscriber class.
2247
+ *
2248
+ * The class will be instantiated when startAll() is called.
2249
+ *
2250
+ * @param subscriberClass - A subclass of BaseSubscriber
2251
+ */
2252
+ register(subscriberClass: SubscriberClass): void;
2253
+ /**
2254
+ * Register a subscriber instance directly.
2255
+ *
2256
+ * Use this when your subscriber needs custom initialization.
2257
+ *
2258
+ * @param subscriber - A subscriber instance
2259
+ */
2260
+ registerInstance(subscriber: BaseSubscriber): void;
2261
+ /**
2262
+ * Start all registered subscribers.
2263
+ *
2264
+ * @param poller - The event poller to register subscribers with
2265
+ */
2266
+ startAll(poller: InProcessDomainEventPoller): void;
2267
+ /**
2268
+ * Stop all subscribers.
2269
+ */
2270
+ stopAll(): void;
2271
+ /**
2272
+ * Check if subscribers have been started.
2273
+ */
2274
+ get isStarted(): boolean;
2275
+ /**
2276
+ * Get count of registered subscribers (classes + instances).
2277
+ */
2278
+ get count(): number;
2279
+ /**
2280
+ * Get subscriber statistics.
2281
+ */
2282
+ get stats(): SubscriberStats;
2283
+ /**
2284
+ * Reset the registry (for testing).
2285
+ */
2286
+ reset(): void;
2287
+ }
2288
+ /**
2289
+ * Callback type for domain event handlers.
2290
+ */
2291
+ type DomainEventCallback = (event: DomainEvent) => void | Promise<void>;
2292
+ /**
2293
+ * Error callback type for domain event processing.
2294
+ */
2295
+ type DomainEventErrorCallback = (error: Error) => void;
2296
+ /**
2297
+ * Poller statistics.
2298
+ */
2299
+ interface PollerStats {
2300
+ /** Total poll cycles */
2301
+ readonly pollCount: number;
2302
+ /** Total events processed */
2303
+ readonly eventsProcessed: number;
2304
+ /** Events that lagged (couldn't keep up) */
2305
+ readonly eventsLagged: number;
2306
+ /** Whether the poller is running */
2307
+ readonly running: boolean;
2308
+ }
2309
+ /**
2310
+ * Poller configuration.
2311
+ */
2312
+ interface DomainEventPollerConfig {
2313
+ /** Polling interval in milliseconds (default: 10) */
2314
+ readonly pollIntervalMs?: number;
2315
+ /** Maximum events per poll cycle (default: 100) */
2316
+ readonly maxEventsPerPoll?: number;
2317
+ }
2318
+ /**
2319
+ * In-process domain event poller.
2320
+ *
2321
+ * Polls for fast domain events from the Rust broadcast channel and
2322
+ * dispatches them to registered subscribers.
2323
+ *
2324
+ * Threading Model:
2325
+ * - Main Thread: TypeScript application, event handlers
2326
+ * - Poll Loop: Async timer-based polling
2327
+ * - Rust: Rust worker runtime (separate from TypeScript)
2328
+ *
2329
+ * @example
2330
+ * ```typescript
2331
+ * const poller = new InProcessDomainEventPoller({
2332
+ * pollIntervalMs: 10,
2333
+ * maxEventsPerPoll: 100,
2334
+ * });
2335
+ *
2336
+ * // Subscribe to patterns
2337
+ * poller.subscribe('payment.*', (event) => {
2338
+ * console.log('Payment event:', event.eventName);
2339
+ * });
2340
+ *
2341
+ * // Start polling
2342
+ * poller.start();
2343
+ *
2344
+ * // Stop when done
2345
+ * poller.stop();
2346
+ * ```
2347
+ */
2348
+ declare class InProcessDomainEventPoller {
2349
+ private readonly pollIntervalMs;
2350
+ private readonly maxEventsPerPoll;
2351
+ private running;
2352
+ private pollTimer;
2353
+ private readonly logger;
2354
+ private readonly subscriptions;
2355
+ private readonly errorCallbacks;
2356
+ private pollCount;
2357
+ private eventsProcessed;
2358
+ private eventsLagged;
2359
+ private pollFn;
2360
+ constructor(config?: DomainEventPollerConfig);
2361
+ /**
2362
+ * Set the FFI poll function.
2363
+ *
2364
+ * This must be called before start() to enable actual polling.
2365
+ * Without it, the poller runs in "dry" mode (for testing).
2366
+ *
2367
+ * @param pollFn - Function that polls for events from Rust
2368
+ */
2369
+ setPollFunction(pollFn: () => DomainEvent | null): void;
2370
+ /**
2371
+ * Subscribe to events matching a pattern.
2372
+ *
2373
+ * @param pattern - Event pattern (e.g., "*", "payment.*")
2374
+ * @param callback - Function to call when events match
2375
+ */
2376
+ subscribe(pattern: string, callback: DomainEventCallback): void;
2377
+ /**
2378
+ * Unsubscribe from a pattern.
2379
+ *
2380
+ * @param pattern - The pattern to unsubscribe from
2381
+ */
2382
+ unsubscribe(pattern: string): void;
2383
+ /**
2384
+ * Register an error callback.
2385
+ */
2386
+ onError(callback: DomainEventErrorCallback): void;
2387
+ /**
2388
+ * Start the polling loop.
2389
+ */
2390
+ start(): void;
2391
+ /**
2392
+ * Stop the polling loop.
2393
+ */
2394
+ stop(): void;
2395
+ /**
2396
+ * Check if the poller is running.
2397
+ */
2398
+ get isRunning(): boolean;
2399
+ /**
2400
+ * Get poller statistics.
2401
+ */
2402
+ get stats(): PollerStats;
2403
+ /**
2404
+ * Schedule the next poll cycle.
2405
+ */
2406
+ private schedulePoll;
2407
+ /**
2408
+ * Execute a poll cycle.
2409
+ */
2410
+ private pollCycle;
2411
+ /**
2412
+ * Dispatch an event to matching subscribers.
2413
+ */
2414
+ private dispatchEvent;
2415
+ /**
2416
+ * Check if an event name matches a pattern.
2417
+ */
2418
+ private matchesPattern;
2419
+ /**
2420
+ * Emit an error to registered callbacks.
2421
+ */
2422
+ private emitError;
2423
+ }
2424
+ /**
2425
+ * Create a StepEventContext from step data.
2426
+ *
2427
+ * @param data - Raw step context data
2428
+ * @returns StepEventContext
2429
+ */
2430
+ declare function createStepEventContext(data: {
2431
+ taskUuid: string;
2432
+ stepUuid: string;
2433
+ stepName: string;
2434
+ namespace?: string;
2435
+ correlationId?: string;
2436
+ result?: Record<string, unknown>;
2437
+ metadata?: Record<string, unknown>;
2438
+ }): StepEventContext;
2439
+ /**
2440
+ * Create a DomainEvent from raw data.
2441
+ *
2442
+ * @param data - Raw event data
2443
+ * @returns DomainEvent
2444
+ */
2445
+ declare function createDomainEvent(data: {
2446
+ eventId: string;
2447
+ eventName: string;
2448
+ payload: Record<string, unknown>;
2449
+ metadata: Record<string, unknown>;
2450
+ executionResult: StepResult;
2451
+ }): DomainEvent;
2452
+ /**
2453
+ * Transform an FfiDomainEvent to a DomainEvent.
2454
+ *
2455
+ * The FFI domain event has a simpler structure than the full DomainEvent.
2456
+ * This function converts between them, synthesizing missing fields.
2457
+ *
2458
+ * @param ffiEvent - Event from FFI poll_in_process_events
2459
+ * @returns DomainEvent suitable for subscribers
2460
+ */
2461
+ declare function ffiEventToDomainEvent(ffiEvent: FfiDomainEvent): DomainEvent;
2462
+ /**
2463
+ * Create an FFI poll function adapter for InProcessDomainEventPoller.
2464
+ *
2465
+ * This function wraps the runtime's pollInProcessEvents() to return
2466
+ * DomainEvent objects that the poller expects.
2467
+ *
2468
+ * @param runtime - The FFI runtime instance
2469
+ * @returns A poll function that returns DomainEvent | null
2470
+ *
2471
+ * @example
2472
+ * ```typescript
2473
+ * const poller = new InProcessDomainEventPoller();
2474
+ * poller.setPollFunction(createFfiPollAdapter(runtime));
2475
+ * poller.start();
2476
+ * ```
2477
+ */
2478
+ declare function createFfiPollAdapter(runtime: TaskerRuntime): () => DomainEvent | null;
2479
+
2480
+ /**
2481
+ * TAS-93: Handler definition type for resolver chain.
2482
+ *
2483
+ * Represents the configuration for a step handler, including:
2484
+ * - callable: The handler address/identifier
2485
+ * - method: Optional method to invoke (defaults to "call")
2486
+ * - resolver: Optional resolver hint to bypass chain
2487
+ * - initialization: Optional configuration passed to handler
2488
+ *
2489
+ * @example
2490
+ * ```typescript
2491
+ * const definition: HandlerDefinition = {
2492
+ * callable: 'payment_handler',
2493
+ * method: 'refund',
2494
+ * resolver: 'explicit_mapping',
2495
+ * initialization: { apiKey: 'secret' },
2496
+ * };
2497
+ *
2498
+ * // Check if method dispatch is needed
2499
+ * if (usesMethodDispatch(definition)) {
2500
+ * // Wrap handler for method dispatch
2501
+ * }
2502
+ * ```
2503
+ */
2504
+
2505
+ /**
2506
+ * Handler definition with resolution metadata.
2507
+ */
2508
+ interface HandlerDefinition {
2509
+ /** The handler address/identifier (required) */
2510
+ callable: string;
2511
+ /** Method to invoke on the handler (defaults to "call") */
2512
+ method?: string | null;
2513
+ /** Resolver hint to bypass chain resolution */
2514
+ resolver?: string | null;
2515
+ /** Initialization configuration passed to handler */
2516
+ initialization?: Record<string, unknown>;
2517
+ }
2518
+ /**
2519
+ * Get the effective method to invoke.
2520
+ *
2521
+ * @param definition - Handler definition
2522
+ * @returns The method name (defaults to "call")
2523
+ */
2524
+ declare function effectiveMethod(definition: HandlerDefinition): string;
2525
+ /**
2526
+ * Check if method dispatch is needed.
2527
+ *
2528
+ * Returns true if a non-default method is specified.
2529
+ *
2530
+ * @param definition - Handler definition
2531
+ * @returns True if method dispatch wrapper is needed
2532
+ */
2533
+ declare function usesMethodDispatch(definition: HandlerDefinition): boolean;
2534
+ /**
2535
+ * Check if a resolver hint is provided.
2536
+ *
2537
+ * @param definition - Handler definition
2538
+ * @returns True if resolver hint should be used
2539
+ */
2540
+ declare function hasResolverHint(definition: HandlerDefinition): boolean;
2541
+ /**
2542
+ * Create a HandlerDefinition from a callable string.
2543
+ *
2544
+ * @param callable - Handler callable string
2545
+ * @returns HandlerDefinition with defaults
2546
+ */
2547
+ declare function fromCallable(callable: string): HandlerDefinition;
2548
+ /**
2549
+ * Create a HandlerDefinition from FFI DTO.
2550
+ *
2551
+ * Maps Rust field names to TypeScript:
2552
+ * - Rust uses 'method' field (matches our interface)
2553
+ *
2554
+ * @param dto - FFI handler definition DTO
2555
+ * @returns HandlerDefinition
2556
+ */
2557
+ declare function fromDto(dto: HandlerDefinitionDto | null | undefined): HandlerDefinition;
2558
+ /**
2559
+ * Type alias for handler specification input.
2560
+ *
2561
+ * Accepts:
2562
+ * - string: Simple callable name
2563
+ * - HandlerDefinition: Full definition with method/resolver
2564
+ * - HandlerDefinitionDto: FFI DTO from Rust
2565
+ */
2566
+ type HandlerSpec = string | HandlerDefinition | HandlerDefinitionDto;
2567
+ /**
2568
+ * Normalize any handler spec to HandlerDefinition.
2569
+ *
2570
+ * @param spec - Handler specification (string, definition, or DTO)
2571
+ * @returns Normalized HandlerDefinition
2572
+ */
2573
+ declare function normalizeToDefinition(spec: HandlerSpec): HandlerDefinition;
2574
+
2575
+ /**
2576
+ * TAS-93: Base resolver interface for step handler resolution.
2577
+ *
2578
+ * Defines the contract that all resolvers must implement.
2579
+ * Resolvers are ordered by priority (lower = checked first).
2580
+ *
2581
+ * @example
2582
+ * ```typescript
2583
+ * class MyResolver implements BaseResolver {
2584
+ * readonly name = 'my_resolver';
2585
+ * readonly priority = 50;
2586
+ *
2587
+ * canResolve(definition: HandlerDefinition): boolean {
2588
+ * return definition.callable.startsWith('my:');
2589
+ * }
2590
+ *
2591
+ * async resolve(definition: HandlerDefinition): Promise<StepHandler | null> {
2592
+ * if (!this.canResolve(definition)) return null;
2593
+ * return new MyHandler();
2594
+ * }
2595
+ * }
2596
+ * ```
2597
+ */
2598
+
2599
+ /**
2600
+ * Configuration passed to resolvers during resolution.
2601
+ */
2602
+ interface ResolverConfig {
2603
+ /** Additional context for resolution */
2604
+ [key: string]: unknown;
2605
+ }
2606
+ /**
2607
+ * Base interface for step handler resolvers.
2608
+ *
2609
+ * Resolvers are responsible for finding and instantiating handlers
2610
+ * based on their callable format. Multiple resolvers form a chain,
2611
+ * ordered by priority.
2612
+ */
2613
+ interface BaseResolver {
2614
+ /**
2615
+ * Unique name for this resolver.
2616
+ * Used for resolver hints and debugging.
2617
+ */
2618
+ readonly name: string;
2619
+ /**
2620
+ * Priority in the resolver chain.
2621
+ * Lower values are checked first.
2622
+ *
2623
+ * Suggested ranges:
2624
+ * - 1-20: Explicit mappings (highest priority)
2625
+ * - 21-50: Custom domain resolvers
2626
+ * - 51-99: Pattern-based resolvers
2627
+ * - 100+: Inferential resolvers (lowest priority)
2628
+ */
2629
+ readonly priority: number;
2630
+ /**
2631
+ * Check if this resolver can handle the given definition.
2632
+ *
2633
+ * This is a quick check without actually resolving.
2634
+ * Used to determine if resolve() should be called.
2635
+ *
2636
+ * @param definition - Handler definition to check
2637
+ * @param config - Optional resolver configuration
2638
+ * @returns True if this resolver can attempt resolution
2639
+ */
2640
+ canResolve(definition: HandlerDefinition, config?: ResolverConfig): boolean;
2641
+ /**
2642
+ * Resolve a handler from the definition.
2643
+ *
2644
+ * Should return null if resolution fails (allows chain to continue).
2645
+ * Should throw only for unrecoverable errors.
2646
+ *
2647
+ * @param definition - Handler definition to resolve
2648
+ * @param config - Optional resolver configuration
2649
+ * @returns Handler instance or null if not found
2650
+ */
2651
+ resolve(definition: HandlerDefinition, config?: ResolverConfig): Promise<StepHandler | null>;
2652
+ }
2653
+
2654
+ /**
2655
+ * TAS-93: Error types for resolver chain.
2656
+ */
2657
+ /**
2658
+ * Base error class for resolution errors.
2659
+ */
2660
+ declare class ResolutionError extends Error {
2661
+ constructor(message: string);
2662
+ }
2663
+ /**
2664
+ * Error thrown when a specified resolver is not found.
2665
+ */
2666
+ declare class ResolverNotFoundError extends ResolutionError {
2667
+ readonly resolverName: string;
2668
+ constructor(resolverName: string);
2669
+ }
2670
+ /**
2671
+ * Error thrown when no resolver can handle a callable.
2672
+ */
2673
+ declare class NoResolverMatchError extends ResolutionError {
2674
+ readonly callable: string;
2675
+ readonly triedResolvers: string[];
2676
+ constructor(callable: string, triedResolvers: string[]);
2677
+ }
2678
+ /**
2679
+ * Error thrown when method dispatch fails.
2680
+ */
2681
+ declare class MethodDispatchError extends ResolutionError {
2682
+ readonly handlerName: string;
2683
+ readonly methodName: string;
2684
+ constructor(handlerName: string, methodName: string);
2685
+ }
2686
+
2687
+ /**
2688
+ * TAS-93: Method dispatch wrapper for step handlers.
2689
+ *
2690
+ * Wraps a handler to redirect .call() invocations to a specified method.
2691
+ * This enables the `handler_method` field to work transparently.
2692
+ *
2693
+ * @example
2694
+ * ```typescript
2695
+ * class PaymentHandler extends StepHandler {
2696
+ * static handlerName = 'payment_handler';
2697
+ *
2698
+ * async call(context: StepContext): Promise<StepHandlerResult> {
2699
+ * return this.success({ action: 'default' });
2700
+ * }
2701
+ *
2702
+ * async refund(context: StepContext): Promise<StepHandlerResult> {
2703
+ * return this.success({ action: 'refund' });
2704
+ * }
2705
+ * }
2706
+ *
2707
+ * // Without wrapper: handler.call(ctx) returns { action: 'default' }
2708
+ * // With wrapper:
2709
+ * const wrapped = new MethodDispatchWrapper(handler, 'refund');
2710
+ * await wrapped.call(ctx); // returns { action: 'refund' }
2711
+ * ```
2712
+ */
2713
+
2714
+ /**
2715
+ * Wrapper that redirects .call() to a specified method.
2716
+ *
2717
+ * Implements ExecutableHandler to be type-safe when used in place of
2718
+ * a regular StepHandler. This avoids unsafe type casting while providing
2719
+ * the same public interface.
2720
+ */
2721
+ declare class MethodDispatchWrapper implements ExecutableHandler {
2722
+ /** The wrapped handler instance */
2723
+ readonly handler: StepHandler;
2724
+ /** The method to invoke instead of call() */
2725
+ readonly targetMethod: string;
2726
+ /** The bound method function */
2727
+ private readonly boundMethod;
2728
+ /**
2729
+ * Create a new method dispatch wrapper.
2730
+ *
2731
+ * @param handler - The handler to wrap
2732
+ * @param targetMethod - The method name to invoke
2733
+ * @throws MethodDispatchError if handler doesn't have the method
2734
+ */
2735
+ constructor(handler: StepHandler, targetMethod: string);
2736
+ /**
2737
+ * Get the handler name.
2738
+ * Delegates to wrapped handler.
2739
+ */
2740
+ get name(): string;
2741
+ /**
2742
+ * Get the handler version.
2743
+ * Delegates to wrapped handler.
2744
+ */
2745
+ get version(): string;
2746
+ /**
2747
+ * Get the handler capabilities.
2748
+ * Delegates to wrapped handler.
2749
+ */
2750
+ get capabilities(): string[];
2751
+ /**
2752
+ * Execute the step by calling the target method.
2753
+ *
2754
+ * @param context - Step execution context
2755
+ * @returns Handler result from the target method
2756
+ */
2757
+ call(context: StepContext): Promise<StepHandlerResult>;
2758
+ /**
2759
+ * Get config schema from wrapped handler.
2760
+ */
2761
+ configSchema(): Record<string, unknown> | null;
2762
+ /**
2763
+ * Get the unwrapped handler.
2764
+ *
2765
+ * Useful for testing and debugging.
2766
+ *
2767
+ * @returns The original handler instance
2768
+ */
2769
+ unwrap(): StepHandler;
2770
+ /**
2771
+ * String representation for debugging.
2772
+ */
2773
+ toString(): string;
2774
+ }
2775
+
2776
+ /**
2777
+ * TAS-93: Developer-friendly base class for custom resolvers.
2778
+ *
2779
+ * Provides pattern and prefix matching capabilities for implementing
2780
+ * custom domain-specific resolvers.
2781
+ *
2782
+ * @example
2783
+ * ```typescript
2784
+ * class PaymentResolver extends RegistryResolver {
2785
+ * static readonly _name = 'payment_resolver';
2786
+ * static readonly _priority = 20;
2787
+ * static readonly pattern = /^payments:(?<provider>\w+):(?<action>\w+)$/;
2788
+ *
2789
+ * async resolveHandler(
2790
+ * definition: HandlerDefinition,
2791
+ * match: RegExpMatchArray | null
2792
+ * ): Promise<StepHandler | null> {
2793
+ * if (!match?.groups) return null;
2794
+ *
2795
+ * const { provider, action } = match.groups;
2796
+ * return PaymentHandlers.get(provider, action);
2797
+ * }
2798
+ * }
2799
+ *
2800
+ * // Register with chain
2801
+ * chain.addResolver(new PaymentResolver());
2802
+ *
2803
+ * // Resolves: { callable: 'payments:stripe:refund' }
2804
+ * ```
2805
+ */
2806
+
2807
+ /**
2808
+ * Static configuration for RegistryResolver subclasses.
2809
+ */
2810
+ interface RegistryResolverStatic {
2811
+ /** Resolver name (required) */
2812
+ readonly _name: string;
2813
+ /** Priority in chain (default: 50) */
2814
+ readonly _priority?: number;
2815
+ /** Regex pattern to match callables (optional) */
2816
+ readonly pattern?: RegExp;
2817
+ /** String prefix to match callables (optional) */
2818
+ readonly prefix?: string;
2819
+ }
2820
+ /**
2821
+ * Developer-friendly base class for custom resolvers.
2822
+ *
2823
+ * Subclasses should:
2824
+ * 1. Set static `_name` and optionally `_priority`
2825
+ * 2. Set static `pattern` or `prefix` for matching
2826
+ * 3. Implement `resolveHandler()` for resolution logic
2827
+ */
2828
+ declare abstract class RegistryResolver implements BaseResolver {
2829
+ /**
2830
+ * Get the resolver name from static property.
2831
+ */
2832
+ get name(): string;
2833
+ /**
2834
+ * Get the resolver priority from static property.
2835
+ */
2836
+ get priority(): number;
2837
+ /**
2838
+ * Check if this resolver can handle the definition.
2839
+ *
2840
+ * Uses pattern or prefix matching from static properties.
2841
+ *
2842
+ * @param definition - Handler definition
2843
+ * @param _config - Unused, part of interface
2844
+ * @returns True if callable matches
2845
+ */
2846
+ canResolve(definition: HandlerDefinition, _config?: ResolverConfig): boolean;
2847
+ /**
2848
+ * Resolve the handler.
2849
+ *
2850
+ * Delegates to resolveHandler() with pattern match if applicable.
2851
+ *
2852
+ * @param definition - Handler definition
2853
+ * @param config - Resolver configuration
2854
+ * @returns Handler instance or null
2855
+ */
2856
+ resolve(definition: HandlerDefinition, config?: ResolverConfig): Promise<StepHandler | null>;
2857
+ /**
2858
+ * Override this in subclasses for custom resolution logic.
2859
+ *
2860
+ * @param definition - Handler definition
2861
+ * @param match - Regex match result (if pattern was used)
2862
+ * @param config - Resolver configuration
2863
+ * @returns Handler instance or null
2864
+ */
2865
+ abstract resolveHandler(definition: HandlerDefinition, match: RegExpMatchArray | null, config?: ResolverConfig): Promise<StepHandler | null>;
2866
+ }
2867
+
2868
+ /**
2869
+ * TAS-93: Resolver chain for step handler resolution.
2870
+ *
2871
+ * Orchestrates multiple resolvers in priority order to find handlers.
2872
+ * Supports resolver hints to bypass the chain and method dispatch wrapping.
2873
+ *
2874
+ * @example
2875
+ * ```typescript
2876
+ * // Create chain with default resolvers
2877
+ * const chain = ResolverChain.default();
2878
+ *
2879
+ * // Register a handler
2880
+ * const explicit = chain.getResolver('explicit_mapping') as ExplicitMappingResolver;
2881
+ * explicit.register('my_handler', MyHandler);
2882
+ *
2883
+ * // Resolve handler
2884
+ * const definition: HandlerDefinition = { callable: 'my_handler' };
2885
+ * const handler = await chain.resolve(definition);
2886
+ *
2887
+ * // Resolve with method dispatch
2888
+ * const definition2: HandlerDefinition = {
2889
+ * callable: 'my_handler',
2890
+ * method: 'process',
2891
+ * };
2892
+ * const handler2 = await chain.resolve(definition2);
2893
+ * // handler2.call() will invoke handler.process()
2894
+ * ```
2895
+ */
2896
+
2897
+ /**
2898
+ * Priority-ordered chain of resolvers for handler resolution.
2899
+ */
2900
+ declare class ResolverChain {
2901
+ private resolvers;
2902
+ private resolversByName;
2903
+ /**
2904
+ * Create a resolver chain with default resolvers.
2905
+ *
2906
+ * Default resolvers:
2907
+ * - ExplicitMappingResolver (priority 10)
2908
+ * - ClassLookupResolver (priority 100)
2909
+ *
2910
+ * Note: Uses Promise caching to prevent race conditions when called
2911
+ * concurrently. Multiple callers will receive the same chain instance.
2912
+ *
2913
+ * @returns Configured resolver chain
2914
+ */
2915
+ static default(): Promise<ResolverChain>;
2916
+ /**
2917
+ * Reset the default chain (for testing only).
2918
+ *
2919
+ * @internal
2920
+ */
2921
+ static resetDefault(): void;
2922
+ /**
2923
+ * Internal method to create the default chain.
2924
+ */
2925
+ private static createDefaultChain;
2926
+ /**
2927
+ * Create a resolver chain synchronously with provided resolvers.
2928
+ *
2929
+ * Use this when you want to avoid async initialization.
2930
+ *
2931
+ * @param resolvers - Resolvers to add to the chain
2932
+ * @returns Configured resolver chain
2933
+ */
2934
+ static withResolvers(resolvers: BaseResolver[]): ResolverChain;
2935
+ /**
2936
+ * Add a resolver to the chain.
2937
+ *
2938
+ * Resolvers are automatically sorted by priority (lowest first).
2939
+ *
2940
+ * @param resolver - Resolver to add
2941
+ */
2942
+ addResolver(resolver: BaseResolver): void;
2943
+ /**
2944
+ * Get a resolver by name.
2945
+ *
2946
+ * @param name - Resolver name
2947
+ * @returns Resolver or undefined if not found
2948
+ */
2949
+ getResolver(name: string): BaseResolver | undefined;
2950
+ /**
2951
+ * List all resolvers with their priorities.
2952
+ *
2953
+ * @returns Array of [name, priority] tuples, sorted by priority
2954
+ */
2955
+ listResolvers(): Array<[string, number]>;
2956
+ /**
2957
+ * Resolve a handler from a definition.
2958
+ *
2959
+ * Resolution process:
2960
+ * 1. If resolver hint is present, use only that resolver
2961
+ * 2. Otherwise, try resolvers in priority order
2962
+ * 3. If method dispatch is needed, wrap the handler
2963
+ *
2964
+ * @param definition - Handler definition to resolve
2965
+ * @param config - Optional resolver configuration
2966
+ * @returns ExecutableHandler instance (possibly wrapped) or null
2967
+ */
2968
+ resolve(definition: HandlerDefinition, config?: ResolverConfig): Promise<ExecutableHandler | null>;
2969
+ /**
2970
+ * Wrap a handler for method dispatch if needed.
2971
+ *
2972
+ * @param handler - Handler to potentially wrap
2973
+ * @param definition - Handler definition with method info
2974
+ * @returns Original handler or MethodDispatchWrapper (both implement ExecutableHandler)
2975
+ */
2976
+ wrapForMethodDispatch(handler: StepHandler, definition: HandlerDefinition): ExecutableHandler;
2977
+ /**
2978
+ * Resolve using a specific resolver (from hint).
2979
+ */
2980
+ private resolveWithHint;
2981
+ /**
2982
+ * Resolve by trying resolvers in priority order.
2983
+ */
2984
+ private resolveWithChain;
2985
+ /**
2986
+ * Sort resolvers by priority (ascending).
2987
+ */
2988
+ private sortResolvers;
2989
+ }
2990
+
2991
+ /**
2992
+ * TAS-93: Class lookup resolver (priority 100).
2993
+ *
2994
+ * Infers handler classes from callable strings using dynamic imports.
2995
+ * This resolver handles module path formats.
2996
+ *
2997
+ * Supports callable formats:
2998
+ * - "./path/to/handler.js" - Relative module path
2999
+ * - "../parent/handler.js" - Parent-relative module path
3000
+ * - "@scope/package/handler" - Scoped package path
3001
+ *
3002
+ * NOT supported (security):
3003
+ * - "/absolute/path/to/handler.js" - Absolute paths are blocked to prevent
3004
+ * loading arbitrary code in shared hosting environments.
3005
+ *
3006
+ * The module must export a class with a static `handlerName` property
3007
+ * matching the expected handler interface.
3008
+ *
3009
+ * Note: This resolver is lower priority (100) because dynamic imports
3010
+ * are more expensive than explicit mappings.
3011
+ *
3012
+ * @example
3013
+ * ```typescript
3014
+ * const resolver = new ClassLookupResolver();
3015
+ *
3016
+ * // Resolve from module path
3017
+ * const definition: HandlerDefinition = {
3018
+ * callable: './handlers/payment-handler.js',
3019
+ * };
3020
+ * const handler = await resolver.resolve(definition);
3021
+ * ```
3022
+ */
3023
+
3024
+ /**
3025
+ * Resolver that infers handlers from module paths via dynamic import.
3026
+ *
3027
+ * Priority 100 - checked last in the default chain (inferential).
3028
+ */
3029
+ declare class ClassLookupResolver implements BaseResolver {
3030
+ readonly name = "class_lookup";
3031
+ readonly priority = 100;
3032
+ /**
3033
+ * Check if callable looks like an importable path.
3034
+ *
3035
+ * @param definition - Handler definition
3036
+ * @param _config - Unused, part of interface
3037
+ * @returns True if callable matches importable pattern
3038
+ */
3039
+ canResolve(definition: HandlerDefinition, _config?: ResolverConfig): boolean;
3040
+ /**
3041
+ * Resolve handler by dynamically importing the module.
3042
+ *
3043
+ * Looks for:
3044
+ * 1. Default export that is a handler class
3045
+ * 2. Named exports that are handler classes
3046
+ *
3047
+ * @param definition - Handler definition with module path
3048
+ * @param _config - Unused, part of interface
3049
+ * @returns Handler instance or null if not found
3050
+ */
3051
+ resolve(definition: HandlerDefinition, _config?: ResolverConfig): Promise<StepHandler | null>;
3052
+ /**
3053
+ * Find a handler class in a module's exports.
3054
+ */
3055
+ private findHandlerClass;
3056
+ /**
3057
+ * Check if a value is a valid handler class.
3058
+ */
3059
+ private isHandlerClass;
3060
+ /**
3061
+ * Instantiate a handler class.
3062
+ */
3063
+ private instantiateHandler;
3064
+ }
3065
+
3066
+ /**
3067
+ * TAS-93: Explicit mapping resolver (priority 10).
3068
+ *
3069
+ * Resolves handlers from explicitly registered mappings.
3070
+ * This is the highest priority resolver in the default chain.
3071
+ *
3072
+ * Supports registering:
3073
+ * - Handler classes (instantiated on resolve)
3074
+ * - Handler instances (returned directly)
3075
+ * - Factory functions (called with config on resolve)
3076
+ *
3077
+ * @example
3078
+ * ```typescript
3079
+ * const resolver = new ExplicitMappingResolver();
3080
+ *
3081
+ * // Register a class
3082
+ * resolver.register('my_handler', MyHandler);
3083
+ *
3084
+ * // Register an instance
3085
+ * resolver.register('shared_handler', new SharedHandler());
3086
+ *
3087
+ * // Register a factory
3088
+ * resolver.register('configurable_handler', (config) => new ConfigHandler(config));
3089
+ *
3090
+ * // Resolve
3091
+ * const definition: HandlerDefinition = { callable: 'my_handler' };
3092
+ * const handler = await resolver.resolve(definition);
3093
+ * ```
3094
+ */
3095
+
3096
+ /**
3097
+ * Factory function for creating handlers.
3098
+ */
3099
+ type HandlerFactory = (config: ResolverConfig) => StepHandler;
3100
+ /**
3101
+ * Entry types that can be registered.
3102
+ */
3103
+ type HandlerEntry = StepHandlerClass | StepHandler | HandlerFactory;
3104
+ /**
3105
+ * Resolver for explicitly registered handlers.
3106
+ *
3107
+ * Priority 10 - checked first in the default chain.
3108
+ */
3109
+ declare class ExplicitMappingResolver implements BaseResolver {
3110
+ readonly name: string;
3111
+ readonly priority = 10;
3112
+ private handlers;
3113
+ /**
3114
+ * Create an explicit mapping resolver.
3115
+ *
3116
+ * @param name - Resolver name (default: 'explicit_mapping')
3117
+ */
3118
+ constructor(name?: string);
3119
+ /**
3120
+ * Check if a handler is registered for this callable.
3121
+ *
3122
+ * @param definition - Handler definition
3123
+ * @param _config - Unused, part of interface
3124
+ * @returns True if handler is registered
3125
+ */
3126
+ canResolve(definition: HandlerDefinition, _config?: ResolverConfig): boolean;
3127
+ /**
3128
+ * Resolve and instantiate a registered handler.
3129
+ *
3130
+ * @param definition - Handler definition
3131
+ * @param config - Configuration passed to factories
3132
+ * @returns Handler instance or null if not registered
3133
+ */
3134
+ resolve(definition: HandlerDefinition, config?: ResolverConfig): Promise<StepHandler | null>;
3135
+ /**
3136
+ * Register a handler.
3137
+ *
3138
+ * @param key - Handler identifier (matched against definition.callable)
3139
+ * @param handler - Handler class, instance, or factory function
3140
+ */
3141
+ register(key: string, handler: HandlerEntry): void;
3142
+ /**
3143
+ * Unregister a handler.
3144
+ *
3145
+ * @param key - Handler identifier to remove
3146
+ * @returns True if handler was removed, false if not found
3147
+ */
3148
+ unregister(key: string): boolean;
3149
+ /**
3150
+ * Get all registered callable keys.
3151
+ *
3152
+ * @returns Array of registered keys
3153
+ */
3154
+ registeredCallables(): string[];
3155
+ /**
3156
+ * Instantiate a handler from a registered entry.
3157
+ */
3158
+ private instantiateHandler;
3159
+ /**
3160
+ * Check if entry is a handler class.
3161
+ */
3162
+ private isHandlerClass;
3163
+ /**
3164
+ * Instantiate a handler class.
3165
+ */
3166
+ private instantiateClass;
3167
+ }
3168
+
3169
+ /**
3170
+ * TAS-93: Step handler registry with resolver chain support.
3171
+ *
3172
+ * Provides handler registration and resolution using a priority-ordered
3173
+ * resolver chain. Supports method dispatch and resolver hints.
3174
+ *
3175
+ * @example
3176
+ * ```typescript
3177
+ * const registry = new HandlerRegistry();
3178
+ * await registry.initialize();
3179
+ *
3180
+ * // Register a handler
3181
+ * registry.register('my_handler', MyHandler);
3182
+ *
3183
+ * // Simple resolution (string callable)
3184
+ * const handler = await registry.resolve('my_handler');
3185
+ *
3186
+ * // Resolution with method dispatch
3187
+ * const definition: HandlerDefinition = {
3188
+ * callable: 'my_handler',
3189
+ * method: 'process',
3190
+ * };
3191
+ * const handler2 = await registry.resolve(definition);
3192
+ * // handler2.call() invokes handler.process()
3193
+ *
3194
+ * // Resolution with resolver hint
3195
+ * const definition2: HandlerDefinition = {
3196
+ * callable: 'my_handler',
3197
+ * resolver: 'explicit_mapping',
3198
+ * };
3199
+ * const handler3 = await registry.resolve(definition2);
3200
+ * ```
3201
+ */
3202
+
3203
+ /**
3204
+ * Registry for step handler classes.
3205
+ *
3206
+ * TAS-93: Uses ResolverChain for flexible handler resolution
3207
+ * with support for method dispatch and resolver hints.
3208
+ *
3209
+ * Provides handler discovery, registration, and resolution.
3210
+ */
3211
+ declare class HandlerRegistry {
3212
+ private _resolverChain;
3213
+ private _explicitResolver;
3214
+ private _initialized;
3215
+ /** Promise-based lock for initialization to prevent concurrent init */
3216
+ private _initPromise;
3217
+ /** Track registrations so they can be transferred to chain resolver */
3218
+ private _pendingRegistrations;
3219
+ /**
3220
+ * Initialize the registry with default resolvers.
3221
+ *
3222
+ * Must be called before using resolve() with resolver chain features.
3223
+ * For simple register/resolve with strings, lazy initialization is used.
3224
+ */
3225
+ initialize(): Promise<void>;
3226
+ /**
3227
+ * Ensure the registry is initialized.
3228
+ * Uses lazy initialization with proper locking to prevent concurrent init.
3229
+ */
3230
+ private ensureInitialized;
3231
+ /**
3232
+ * Get the explicit mapping resolver for direct registration.
3233
+ */
3234
+ private getExplicitResolver;
3235
+ /**
3236
+ * Register a handler class.
3237
+ *
3238
+ * @param name - Handler name (must match step definition)
3239
+ * @param handlerClass - StepHandler subclass
3240
+ * @throws Error if handlerClass is not a valid StepHandler subclass
3241
+ *
3242
+ * @example
3243
+ * ```typescript
3244
+ * registry.register('my_handler', MyHandler);
3245
+ * ```
3246
+ */
3247
+ register(name: string, handlerClass: StepHandlerClass): void;
3248
+ /**
3249
+ * Unregister a handler.
3250
+ *
3251
+ * @param name - Handler name to unregister
3252
+ * @returns True if handler was unregistered, false if not found
3253
+ */
3254
+ unregister(name: string): boolean;
3255
+ /**
3256
+ * Resolve and instantiate a handler.
3257
+ *
3258
+ * TAS-93: Accepts flexible input types:
3259
+ * - string: Simple callable name
3260
+ * - HandlerDefinition: Full definition with method/resolver
3261
+ * - HandlerSpec: Union type for all formats
3262
+ *
3263
+ * @param handlerSpec - Handler specification
3264
+ * @returns ExecutableHandler (StepHandler or MethodDispatchWrapper) or null if not found
3265
+ *
3266
+ * @example
3267
+ * ```typescript
3268
+ * // String callable
3269
+ * const handler = await registry.resolve('my_handler');
3270
+ *
3271
+ * // With method dispatch
3272
+ * const handler2 = await registry.resolve({
3273
+ * callable: 'my_handler',
3274
+ * method: 'process',
3275
+ * });
3276
+ * ```
3277
+ */
3278
+ resolve(handlerSpec: HandlerSpec): Promise<ExecutableHandler | null>;
3279
+ /**
3280
+ * Synchronous resolve for backward compatibility.
3281
+ *
3282
+ * Note: This only works with explicitly registered handlers.
3283
+ * For full resolver chain support, use the async resolve() method.
3284
+ *
3285
+ * @param name - Handler name to resolve
3286
+ * @returns Instantiated handler or null if not found
3287
+ */
3288
+ resolveSync(name: string): StepHandler | null;
3289
+ /**
3290
+ * Get a handler class without instantiation.
3291
+ *
3292
+ * @param name - Handler name to look up
3293
+ * @returns Handler class or undefined if not found
3294
+ */
3295
+ getHandlerClass(_name: string): StepHandlerClass | undefined;
3296
+ /**
3297
+ * Check if a handler is registered.
3298
+ *
3299
+ * @param name - Handler name to check
3300
+ * @returns True if handler is registered
3301
+ */
3302
+ isRegistered(name: string): boolean;
3303
+ /**
3304
+ * List all registered handler names.
3305
+ *
3306
+ * @returns Array of registered handler names
3307
+ */
3308
+ listHandlers(): string[];
3309
+ /**
3310
+ * Get the number of registered handlers.
3311
+ */
3312
+ handlerCount(): number;
3313
+ /**
3314
+ * Clear all registered handlers.
3315
+ */
3316
+ clear(): void;
3317
+ /**
3318
+ * Add a custom resolver to the chain.
3319
+ *
3320
+ * TAS-93: Allows adding custom domain-specific resolvers.
3321
+ *
3322
+ * @param resolver - Resolver to add
3323
+ */
3324
+ addResolver(resolver: BaseResolver): Promise<void>;
3325
+ /**
3326
+ * Get a resolver by name.
3327
+ *
3328
+ * @param name - Resolver name
3329
+ * @returns Resolver or undefined
3330
+ */
3331
+ getResolver(name: string): Promise<BaseResolver | undefined>;
3332
+ /**
3333
+ * List all resolvers with priorities.
3334
+ *
3335
+ * @returns Array of [name, priority] tuples
3336
+ */
3337
+ listResolvers(): Promise<Array<[string, number]>>;
3338
+ /**
3339
+ * Get the underlying resolver chain.
3340
+ *
3341
+ * Useful for advanced configuration.
3342
+ */
3343
+ getResolverChain(): Promise<ResolverChain | null>;
3344
+ /**
3345
+ * Get debug information about the registry.
3346
+ */
3347
+ debugInfo(): Record<string, unknown>;
3348
+ }
3349
+
3350
+ /**
3351
+ * HandlerSystem - Owns handler registration and discovery.
3352
+ *
3353
+ * TAS-93: Uses HandlerRegistry with resolver chain for flexible handler resolution.
3354
+ *
3355
+ * This class encapsulates handler management:
3356
+ * - Owns a HandlerRegistry instance (no singleton)
3357
+ * - Provides handler discovery from directories
3358
+ * - Manages handler registration lifecycle
3359
+ * - Full resolver chain support via HandlerRegistry
3360
+ *
3361
+ * Design principles:
3362
+ * - Explicit construction: No singleton pattern
3363
+ * - Clear ownership: Owns the registry instance
3364
+ * - Encapsulated discovery: Handler loading logic contained here
3365
+ * - Single registry: Uses HandlerRegistry for all resolution
3366
+ */
3367
+
3368
+ /**
3369
+ * Owns handler registration and discovery.
3370
+ *
3371
+ * TAS-93: Uses HandlerRegistry internally for unified resolution.
3372
+ *
3373
+ * Unlike using HandlerRegistry directly, this class:
3374
+ * - Encapsulates handler discovery from directories
3375
+ * - Provides convenience methods for loading handlers
3376
+ * - Manages the full handler lifecycle
3377
+ *
3378
+ * @example
3379
+ * ```typescript
3380
+ * const handlerSystem = new HandlerSystem();
3381
+ *
3382
+ * // Register individual handlers
3383
+ * handlerSystem.register('my_handler', MyHandler);
3384
+ *
3385
+ * // Or load from directory
3386
+ * await handlerSystem.loadFromPath('./handlers');
3387
+ *
3388
+ * // Resolve with full resolver chain support
3389
+ * const handler = await handlerSystem.resolve('my_handler');
3390
+ *
3391
+ * // Resolve with method dispatch
3392
+ * const handler2 = await handlerSystem.resolve({
3393
+ * callable: 'my_handler',
3394
+ * method: 'process',
3395
+ * });
3396
+ * ```
3397
+ */
3398
+ declare class HandlerSystem {
3399
+ private readonly registry;
3400
+ /**
3401
+ * Create a new HandlerSystem.
3402
+ */
3403
+ constructor();
3404
+ /**
3405
+ * Initialize the handler system.
3406
+ *
3407
+ * Initializes the underlying HandlerRegistry with resolver chain.
3408
+ * Call this before using resolve() for best performance.
3409
+ */
3410
+ initialize(): Promise<void>;
3411
+ /**
3412
+ * Check if the system is initialized.
3413
+ */
3414
+ get initialized(): boolean;
3415
+ /**
3416
+ * Load handlers from a directory path.
3417
+ *
3418
+ * Searches for handler modules in the directory and registers them.
3419
+ * Supports both index file exports and directory scanning.
3420
+ *
3421
+ * @param path - Path to directory containing handlers
3422
+ * @returns Number of handlers loaded
3423
+ */
3424
+ loadFromPath(path: string): Promise<number>;
3425
+ /**
3426
+ * Load handlers from TYPESCRIPT_HANDLER_PATH environment variable.
3427
+ *
3428
+ * @returns Number of handlers loaded
3429
+ */
3430
+ loadFromEnv(): Promise<number>;
3431
+ /**
3432
+ * Register a handler class.
3433
+ *
3434
+ * @param name - Handler name (must match step definition)
3435
+ * @param handlerClass - StepHandler subclass
3436
+ */
3437
+ register(name: string, handlerClass: StepHandlerClass): void;
3438
+ /**
3439
+ * Unregister a handler.
3440
+ *
3441
+ * @param name - Handler name to unregister
3442
+ * @returns True if handler was unregistered
3443
+ */
3444
+ unregister(name: string): boolean;
3445
+ /**
3446
+ * Resolve and instantiate a handler.
3447
+ *
3448
+ * TAS-93: Supports full resolver chain with method dispatch and resolver hints.
3449
+ *
3450
+ * @param handlerSpec - Handler specification (string, definition, or DTO)
3451
+ * @returns Instantiated handler or null if not found
3452
+ *
3453
+ * @example
3454
+ * ```typescript
3455
+ * // String callable
3456
+ * const handler = await handlerSystem.resolve('my_handler');
3457
+ *
3458
+ * // With method dispatch
3459
+ * const handler2 = await handlerSystem.resolve({
3460
+ * callable: 'my_handler',
3461
+ * method: 'process',
3462
+ * });
3463
+ *
3464
+ * // With resolver hint
3465
+ * const handler3 = await handlerSystem.resolve({
3466
+ * callable: 'my_handler',
3467
+ * resolver: 'explicit_mapping',
3468
+ * });
3469
+ * ```
3470
+ */
3471
+ resolve(handlerSpec: HandlerSpec): Promise<ExecutableHandler | null>;
3472
+ /**
3473
+ * Check if a handler is registered.
3474
+ */
3475
+ isRegistered(name: string): boolean;
3476
+ /**
3477
+ * List all registered handler names.
3478
+ */
3479
+ listHandlers(): string[];
3480
+ /**
3481
+ * Get the number of registered handlers.
3482
+ */
3483
+ handlerCount(): number;
3484
+ /**
3485
+ * Clear all registered handlers.
3486
+ */
3487
+ clear(): void;
3488
+ /**
3489
+ * Add a custom resolver to the chain.
3490
+ *
3491
+ * TAS-93: Allows adding custom domain-specific resolvers.
3492
+ *
3493
+ * @param resolver - Resolver to add
3494
+ */
3495
+ addResolver(resolver: BaseResolver): Promise<void>;
3496
+ /**
3497
+ * Get a resolver by name.
3498
+ *
3499
+ * @param name - Resolver name
3500
+ * @returns Resolver or undefined
3501
+ */
3502
+ getResolver(name: string): Promise<BaseResolver | undefined>;
3503
+ /**
3504
+ * List all resolvers with priorities.
3505
+ *
3506
+ * @returns Array of [name, priority] tuples
3507
+ */
3508
+ listResolvers(): Promise<Array<[string, number]>>;
3509
+ /**
3510
+ * Get the underlying resolver chain.
3511
+ *
3512
+ * Useful for advanced configuration.
3513
+ */
3514
+ getResolverChain(): Promise<ResolverChain | null>;
3515
+ /**
3516
+ * Get the underlying HandlerRegistry.
3517
+ *
3518
+ * TAS-93: Returns the HandlerRegistry directly for use with
3519
+ * StepExecutionSubscriber and other components.
3520
+ */
3521
+ getRegistry(): HandlerRegistry;
3522
+ /**
3523
+ * Get debug information about the handler system.
3524
+ */
3525
+ debugInfo(): Record<string, unknown>;
3526
+ /**
3527
+ * Try to import an index file from the handler path.
3528
+ */
3529
+ private tryImportIndexFile;
3530
+ /**
3531
+ * Register handlers from a module's exports.
3532
+ */
3533
+ private registerHandlersFromModule;
3534
+ /**
3535
+ * Register handlers from ALL_EXAMPLE_HANDLERS array.
3536
+ */
3537
+ private registerFromHandlerArray;
3538
+ /**
3539
+ * Register handlers from module exports.
3540
+ */
3541
+ private registerFromModuleExports;
3542
+ /**
3543
+ * Check if a value is a valid handler class.
3544
+ */
3545
+ private isValidHandlerClass;
3546
+ /**
3547
+ * Recursively scan a directory for handler files and import them.
3548
+ */
3549
+ private scanAndImportHandlers;
3550
+ /**
3551
+ * Process a single directory entry for handler import.
3552
+ */
3553
+ private processDirectoryEntry;
3554
+ /**
3555
+ * Check if a directory should be scanned for handlers.
3556
+ */
3557
+ private shouldScanDirectory;
3558
+ /**
3559
+ * Check if a file might contain handlers.
3560
+ */
3561
+ private isHandlerFile;
3562
+ /**
3563
+ * Import handlers from a single file.
3564
+ */
3565
+ private importHandlerFile;
3566
+ }
3567
+
3568
+ /**
3569
+ * Structured logging API for TypeScript workers.
3570
+ *
3571
+ * Provides unified structured logging that integrates with Rust tracing
3572
+ * infrastructure via FFI. All log messages are forwarded to the Rust
3573
+ * tracing subscriber for consistent formatting and output.
3574
+ *
3575
+ * Matches Python's logging module and Ruby's tracing module (TAS-92 aligned).
3576
+ *
3577
+ * To enable FFI logging, call setLoggingRuntime() after loading the FFI layer.
3578
+ * If no runtime is installed, logs fall back to console output.
3579
+ */
3580
+
3581
+ /**
3582
+ * Structured logging fields.
3583
+ *
3584
+ * All fields are optional. Common fields include:
3585
+ * - component: Component/subsystem identifier (e.g., "handler", "registry")
3586
+ * - operation: Operation being performed (e.g., "process_payment")
3587
+ * - correlation_id: Distributed tracing correlation ID
3588
+ * - task_uuid: Task identifier
3589
+ * - step_uuid: Step identifier
3590
+ * - namespace: Task namespace
3591
+ * - error_message: Error message for error logs
3592
+ * - duration_ms: Execution duration for timed operations
3593
+ */
3594
+ interface LogFields {
3595
+ [key: string]: string | number | boolean | null | undefined;
3596
+ }
3597
+ /**
3598
+ * Log an ERROR level message with structured fields.
3599
+ *
3600
+ * Use this for unrecoverable failures that require intervention.
3601
+ *
3602
+ * @param message - The log message
3603
+ * @param fields - Optional structured fields for context
3604
+ *
3605
+ * @example
3606
+ * logError('Database connection failed', {
3607
+ * component: 'database',
3608
+ * operation: 'connect',
3609
+ * error_message: 'Connection timeout',
3610
+ * });
3611
+ */
3612
+ declare function logError(message: string, fields?: LogFields): void;
3613
+ /**
3614
+ * Log a WARN level message with structured fields.
3615
+ *
3616
+ * Use this for degraded operation or retryable failures.
3617
+ *
3618
+ * @param message - The log message
3619
+ * @param fields - Optional structured fields for context
3620
+ *
3621
+ * @example
3622
+ * logWarn('Retry attempt 3 of 5', {
3623
+ * component: 'handler',
3624
+ * operation: 'retry',
3625
+ * attempt: 3,
3626
+ * });
3627
+ */
3628
+ declare function logWarn(message: string, fields?: LogFields): void;
3629
+ /**
3630
+ * Log an INFO level message with structured fields.
3631
+ *
3632
+ * Use this for lifecycle events and state transitions.
3633
+ *
3634
+ * @param message - The log message
3635
+ * @param fields - Optional structured fields for context
3636
+ *
3637
+ * @example
3638
+ * logInfo('Task processing started', {
3639
+ * component: 'handler',
3640
+ * operation: 'process_payment',
3641
+ * correlation_id: 'abc-123',
3642
+ * task_uuid: 'task-456',
3643
+ * });
3644
+ */
3645
+ declare function logInfo(message: string, fields?: LogFields): void;
3646
+ /**
3647
+ * Log a DEBUG level message with structured fields.
3648
+ *
3649
+ * Use this for detailed diagnostic information during development.
3650
+ *
3651
+ * @param message - The log message
3652
+ * @param fields - Optional structured fields for context
3653
+ *
3654
+ * @example
3655
+ * logDebug('Parsed request payload', {
3656
+ * component: 'handler',
3657
+ * payload_size: 1024,
3658
+ * content_type: 'application/json',
3659
+ * });
3660
+ */
3661
+ declare function logDebug(message: string, fields?: LogFields): void;
3662
+ /**
3663
+ * Log a TRACE level message with structured fields.
3664
+ *
3665
+ * Use this for very verbose logging, like function entry/exit.
3666
+ * This level is typically disabled in production.
3667
+ *
3668
+ * @param message - The log message
3669
+ * @param fields - Optional structured fields for context
3670
+ *
3671
+ * @example
3672
+ * logTrace('Entering process_step', {
3673
+ * component: 'handler',
3674
+ * step_uuid: 'step-789',
3675
+ * });
3676
+ */
3677
+ declare function logTrace(message: string, fields?: LogFields): void;
3678
+ /**
3679
+ * Create a logger with preset fields.
3680
+ *
3681
+ * Useful for creating component-specific loggers that automatically
3682
+ * include common fields in every log message.
3683
+ *
3684
+ * @param defaultFields - Fields to include in every log message
3685
+ * @returns Logger object with log methods
3686
+ *
3687
+ * @example
3688
+ * const logger = createLogger({ component: 'payment_handler' });
3689
+ * logger.info('Processing payment', { amount: 100 });
3690
+ * // Logs: { component: 'payment_handler', amount: 100 }
3691
+ */
3692
+ declare function createLogger(defaultFields: LogFields): {
3693
+ error: (message: string, fields?: LogFields) => void;
3694
+ warn: (message: string, fields?: LogFields) => void;
3695
+ info: (message: string, fields?: LogFields) => void;
3696
+ debug: (message: string, fields?: LogFields) => void;
3697
+ trace: (message: string, fields?: LogFields) => void;
3698
+ };
3699
+
3700
+ /**
3701
+ * Shutdown controller for coordinating graceful shutdown.
3702
+ *
3703
+ * Provides a signal-based mechanism for triggering and awaiting
3704
+ * shutdown across async boundaries.
3705
+ */
3706
+ /**
3707
+ * Shutdown signal handler type.
3708
+ */
3709
+ type ShutdownHandler = () => void | Promise<void>;
3710
+ /**
3711
+ * Controller for coordinating graceful shutdown.
3712
+ *
3713
+ * Provides a promise-based mechanism for waiting on shutdown signals
3714
+ * and executing cleanup handlers in order.
3715
+ *
3716
+ * @example
3717
+ * ```typescript
3718
+ * const shutdown = new ShutdownController();
3719
+ *
3720
+ * process.on('SIGTERM', () => shutdown.trigger('SIGTERM'));
3721
+ * process.on('SIGINT', () => shutdown.trigger('SIGINT'));
3722
+ *
3723
+ * // Wait for shutdown signal
3724
+ * await shutdown.promise;
3725
+ *
3726
+ * // Or check if shutdown was requested
3727
+ * if (shutdown.isRequested) {
3728
+ * await cleanup();
3729
+ * }
3730
+ * ```
3731
+ */
3732
+ declare class ShutdownController {
3733
+ private _shutdownRequested;
3734
+ private _resolver;
3735
+ private _signal;
3736
+ private readonly _handlers;
3737
+ /**
3738
+ * Promise that resolves when shutdown is triggered.
3739
+ */
3740
+ readonly promise: Promise<void>;
3741
+ constructor();
3742
+ /**
3743
+ * Check if shutdown has been requested.
3744
+ */
3745
+ get isRequested(): boolean;
3746
+ /**
3747
+ * Get the signal that triggered shutdown, if any.
3748
+ */
3749
+ get signal(): string | null;
3750
+ /**
3751
+ * Register a handler to be called during shutdown.
3752
+ *
3753
+ * Handlers are called in registration order.
3754
+ */
3755
+ onShutdown(handler: ShutdownHandler): void;
3756
+ /**
3757
+ * Trigger shutdown with the given signal.
3758
+ *
3759
+ * @param signal - The signal that triggered shutdown (e.g., 'SIGTERM', 'SIGINT')
3760
+ */
3761
+ trigger(signal: string): void;
3762
+ /**
3763
+ * Execute all registered shutdown handlers.
3764
+ *
3765
+ * Handlers are called in registration order. Errors are logged
3766
+ * but do not prevent subsequent handlers from running.
3767
+ */
3768
+ executeHandlers(): Promise<void>;
3769
+ /**
3770
+ * Reset the controller for reuse (primarily for testing).
3771
+ */
3772
+ reset(): void;
3773
+ }
3774
+
3775
+ /**
3776
+ * Server module types.
3777
+ *
3778
+ * Defines types for WorkerServer lifecycle and configuration.
3779
+ */
3780
+
3781
+ /**
3782
+ * Server state constants.
3783
+ *
3784
+ * Use these constants instead of raw strings for type safety and consistency.
3785
+ *
3786
+ * State transitions:
3787
+ * - INITIALIZED -> STARTING -> RUNNING -> SHUTTING_DOWN -> STOPPED
3788
+ * - Any state can transition to ERROR on fatal failures
3789
+ */
3790
+ declare const ServerStates: {
3791
+ /** Initial state after construction */
3792
+ readonly INITIALIZED: "initialized";
3793
+ /** Starting up: loading FFI, registering handlers, bootstrapping */
3794
+ readonly STARTING: "starting";
3795
+ /** Running and processing events */
3796
+ readonly RUNNING: "running";
3797
+ /** Graceful shutdown in progress */
3798
+ readonly SHUTTING_DOWN: "shutting_down";
3799
+ /** Fully stopped */
3800
+ readonly STOPPED: "stopped";
3801
+ /** Error state - fatal failure occurred */
3802
+ readonly ERROR: "error";
3803
+ };
3804
+ /**
3805
+ * Server lifecycle states (union type derived from constants).
3806
+ */
3807
+ type ServerState = (typeof ServerStates)[keyof typeof ServerStates];
3808
+ /**
3809
+ * Worker server configuration.
3810
+ *
3811
+ * All fields are optional with sensible defaults.
3812
+ */
3813
+ interface WorkerServerConfig {
3814
+ /** Task namespace to handle (default: "default") */
3815
+ namespace?: string;
3816
+ /** Log level for Rust tracing (default: "info") */
3817
+ logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error';
3818
+ /** Path to TOML configuration file */
3819
+ configPath?: string;
3820
+ /** PostgreSQL database connection URL */
3821
+ databaseUrl?: string;
3822
+ /** Path to the FFI library (overrides auto-discovery) */
3823
+ libraryPath?: string;
3824
+ /** Maximum concurrent handler executions (default: 10) */
3825
+ maxConcurrentHandlers?: number;
3826
+ /** Handler execution timeout in milliseconds (default: 300000 = 5 minutes) */
3827
+ handlerTimeoutMs?: number;
3828
+ /** Event polling interval in milliseconds (default: 10) */
3829
+ pollIntervalMs?: number;
3830
+ /** Starvation check interval in poll cycles (default: 100) */
3831
+ starvationCheckInterval?: number;
3832
+ /** Cleanup interval in poll cycles (default: 1000) */
3833
+ cleanupInterval?: number;
3834
+ /** Metrics reporting interval in poll cycles (default: 100) */
3835
+ metricsInterval?: number;
3836
+ }
3837
+ /**
3838
+ * Health check result.
3839
+ */
3840
+ interface HealthCheckResult {
3841
+ /** Whether the worker is healthy */
3842
+ healthy: boolean;
3843
+ /** Optional status details when healthy */
3844
+ status?: ServerStatus;
3845
+ /** Error message when unhealthy */
3846
+ error?: string;
3847
+ }
3848
+ /**
3849
+ * Server status information.
3850
+ */
3851
+ interface ServerStatus {
3852
+ /** Current server state */
3853
+ state: ServerState;
3854
+ /** Worker identifier */
3855
+ workerId: string | null;
3856
+ /** Whether the worker is actively running */
3857
+ running: boolean;
3858
+ /** Number of events processed */
3859
+ processedCount: number;
3860
+ /** Number of errors encountered */
3861
+ errorCount: number;
3862
+ /** Number of currently active handlers */
3863
+ activeHandlers: number;
3864
+ /** Server uptime in milliseconds */
3865
+ uptimeMs: number;
3866
+ }
3867
+ /**
3868
+ * Internal server components.
3869
+ *
3870
+ * Used by WorkerServer to manage lifecycle of all components.
3871
+ */
3872
+ interface ServerComponents {
3873
+ /** FFI runtime instance */
3874
+ runtime: TaskerRuntime;
3875
+ /** Event emitter for step events */
3876
+ emitter: TaskerEventEmitter;
3877
+ /** Handler registry */
3878
+ registry: HandlerRegistry;
3879
+ /** Event poller for FFI events */
3880
+ eventPoller: EventPoller;
3881
+ /** Step execution subscriber */
3882
+ stepSubscriber: StepExecutionSubscriber;
3883
+ /** Worker identifier from bootstrap */
3884
+ workerId: string;
3885
+ }
3886
+
3887
+ /**
3888
+ * WorkerServer - Orchestrates the TypeScript worker lifecycle.
3889
+ *
3890
+ * Manages the complete lifecycle of a TypeScript worker:
3891
+ * - FFI library loading (via FfiLayer)
3892
+ * - Handler registration (via HandlerSystem)
3893
+ * - Rust worker bootstrapping
3894
+ * - Event processing (via EventSystem)
3895
+ * - Graceful shutdown
3896
+ *
3897
+ * Design principles:
3898
+ * - Explicit construction: No singleton pattern - caller creates and manages
3899
+ * - Clear ownership: Owns FfiLayer, HandlerSystem, EventSystem
3900
+ * - Explicit lifecycle: Clear 3-phase startup and shutdown
3901
+ *
3902
+ * @example
3903
+ * ```typescript
3904
+ * const server = new WorkerServer();
3905
+ *
3906
+ * await server.start({
3907
+ * namespace: 'payments',
3908
+ * logLevel: 'debug',
3909
+ * });
3910
+ *
3911
+ * // Server is now running and processing tasks
3912
+ *
3913
+ * await server.shutdown();
3914
+ * ```
3915
+ */
3916
+
3917
+ /**
3918
+ * Worker server class.
3919
+ *
3920
+ * Unlike the previous singleton pattern, this class is instantiated directly
3921
+ * by the caller (typically bin/server.ts). This provides explicit lifecycle
3922
+ * control and clear dependency ownership.
3923
+ */
3924
+ declare class WorkerServer {
3925
+ private readonly ffiLayer;
3926
+ private readonly handlerSystem;
3927
+ private eventSystem;
3928
+ private state;
3929
+ private config;
3930
+ private workerId;
3931
+ private startTime;
3932
+ private shutdownHandlers;
3933
+ /**
3934
+ * Create a new WorkerServer.
3935
+ *
3936
+ * @param ffiConfig - Optional FFI layer configuration
3937
+ */
3938
+ constructor(ffiConfig?: FfiLayerConfig);
3939
+ /**
3940
+ * Get the current server state.
3941
+ */
3942
+ getState(): ServerState;
3943
+ /**
3944
+ * Get the worker identifier.
3945
+ */
3946
+ getWorkerId(): string | null;
3947
+ /**
3948
+ * Check if the server is currently running.
3949
+ */
3950
+ isRunning(): boolean;
3951
+ /**
3952
+ * Get the handler system for external handler registration.
3953
+ */
3954
+ getHandlerSystem(): HandlerSystem;
3955
+ /**
3956
+ * Get the event system (available after start).
3957
+ */
3958
+ getEventSystem(): EventSystem | null;
3959
+ /**
3960
+ * Start the worker server.
3961
+ *
3962
+ * Three-phase startup:
3963
+ * 1. Initialize: Load FFI, load handlers
3964
+ * 2. Bootstrap: Initialize Rust worker
3965
+ * 3. Start: Begin event processing
3966
+ *
3967
+ * @param config - Optional server configuration
3968
+ * @returns The server instance for chaining
3969
+ * @throws Error if server is already running or fails to start
3970
+ */
3971
+ start(config?: WorkerServerConfig): Promise<this>;
3972
+ /**
3973
+ * Shutdown the worker server gracefully.
3974
+ *
3975
+ * Three-phase shutdown:
3976
+ * 1. Stop event processing
3977
+ * 2. Stop Rust worker
3978
+ * 3. Unload FFI
3979
+ */
3980
+ shutdown(): Promise<void>;
3981
+ /**
3982
+ * Register a handler to be called during shutdown.
3983
+ *
3984
+ * @param handler - Function to execute during shutdown
3985
+ */
3986
+ onShutdown(handler: () => void | Promise<void>): void;
3987
+ /**
3988
+ * Perform a health check on the worker.
3989
+ */
3990
+ healthCheck(): HealthCheckResult;
3991
+ /**
3992
+ * Get detailed server status.
3993
+ */
3994
+ status(): ServerStatus;
3995
+ /**
3996
+ * Phase 1: Initialize FFI and handlers.
3997
+ */
3998
+ private initializePhase;
3999
+ /**
4000
+ * Phase 2: Bootstrap Rust worker.
4001
+ */
4002
+ private bootstrapPhase;
4003
+ /**
4004
+ * Phase 3: Start event processing.
4005
+ */
4006
+ private startEventProcessingPhase;
4007
+ /**
4008
+ * Cleanup on error during startup.
4009
+ */
4010
+ private cleanupOnError;
4011
+ }
4012
+
4013
+ export { type APICapable, APIMixin, ApiHandler, ApiResponse, BasePublisher, type BaseResolver, BaseSubscriber, type BatchAggregationResult, type BatchAnalyzerOutcome, type BatchMetadata, type BatchProcessingOutcome, type BatchWorkerContext, type BatchWorkerOutcome, type Batchable, BatchableMixin, type BootstrapConfig, type BootstrapResult, ClassLookupResolver, type CreateBatchesOutcome, type CursorConfig, type DecisionCapable, DecisionHandler, DecisionMixin, type DecisionPointOutcome, DecisionType, DefaultPublisher, type DomainEvent, type DomainEventCallback, type DomainEventErrorCallback, type DomainEventMetadata, type DomainEventPollerConfig, DuplicatePublisherError, type EventDeclaration, EventPoller, EventSystem, ExecutableHandler, ExplicitMappingResolver, type FailureStrategy, FfiLayerConfig, type HandlerEntry, type HandlerFactory, HandlerRegistry, type HandlerSpec, HandlerSystem, InProcessDomainEventPoller, type LogFields, MethodDispatchError, MethodDispatchWrapper, type NoBatchesOutcome, NoResolverMatchError, type PollerStats, type PublishContext, PublisherNotFoundError, PublisherRegistry, PublisherValidationError, RegistryFrozenError, RegistryResolver, type RegistryResolverStatic, ResolutionError, ResolverChain, type ResolverConfig, ResolverNotFoundError, type RustBatchWorkerInputs, type RustCursorConfig, type ServerComponents, type HealthCheckResult as ServerHealthCheckResult, type ServerState, type ServerStatus, ShutdownController, type ShutdownHandler, StepContext, type StepEventContext, StepExecutionSubscriber, StepHandler, StepHandlerClass, StepHandlerResult, type StepResult, type StopResult, type SubscriberClass, SubscriberRegistry, type SubscriberStats, TaskerEventEmitter, TaskerRuntime, WorkerServer, type WorkerServerConfig, type WorkerStatus, aggregateBatchResults, applyAPI, applyBatchable, applyDecision, bootstrapWorker, createBatchWorkerContext, createBatches, createDomainEvent, createFfiPollAdapter, createLogger, createStepEventContext, effectiveMethod, ffiEventToDomainEvent, fromCallable, fromDto, getRustVersion, getVersion, getWorkerStatus, hasResolverHint, healthCheck, isCreateBatches, isNoBatches, isWorkerRunning, logDebug, logError, logInfo, logTrace, logWarn, noBatches, normalizeToDefinition, stopWorker, transitionToGracefulShutdown, usesMethodDispatch };