@routecraft/routecraft 0.1.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,1454 @@
1
+ import { Logger } from 'pino';
2
+ export { Logger } from 'pino';
3
+ import { StandardSchemaV1 } from '@standard-schema/spec';
4
+
5
+ /**
6
+ * Create a context-aware logger with appropriate metadata.
7
+ *
8
+ * This function creates a logger that includes relevant context information:
9
+ * - For CraftContext: Includes contextId
10
+ * - For Route: Includes contextId and routeId
11
+ * - For Exchange: Includes contextId, routeId, exchangeId, and correlationId
12
+ *
13
+ * @param context The context to create a logger for
14
+ * @returns A configured logger instance
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // Create a logger for a context
19
+ * const contextLogger = createLogger(myContext);
20
+ * contextLogger.info('Context starting');
21
+ *
22
+ * // Create a logger for a route
23
+ * const routeLogger = createLogger(myRoute);
24
+ * routeLogger.debug('Processing route');
25
+ *
26
+ * // Create a logger for an exchange
27
+ * const exchangeLogger = createLogger(exchange);
28
+ * exchangeLogger.info('Processing data', { data: exchange.body });
29
+ * ```
30
+ */
31
+ declare function createLogger(context?: CraftContext | Route | Exchange): Logger;
32
+ /**
33
+ * Default global logger instance.
34
+ *
35
+ * Use this for application-level logging when no specific context is available.
36
+ * For context-specific logging, create a logger using createLogger().
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * // Log application-level messages
41
+ * logger.info('Application starting');
42
+ * logger.error(error, 'Unexpected error occurred');
43
+ * ```
44
+ */
45
+ declare const logger: Logger;
46
+
47
+ interface Adapter {
48
+ }
49
+ interface Step<T extends Adapter> {
50
+ operation: OperationType;
51
+ adapter: T;
52
+ execute(exchange: Exchange, remainingSteps: Step<Adapter>[], queue: {
53
+ exchange: Exchange;
54
+ steps: Step<Adapter>[];
55
+ }[]): Promise<void>;
56
+ }
57
+ type ConsumerType<T extends Consumer, O = unknown> = new (context: CraftContext, definition: RouteDefinition, channel: unknown, options: O) => T;
58
+ type Message = {
59
+ message: unknown;
60
+ headers?: ExchangeHeaders;
61
+ };
62
+ interface Consumer<O = unknown> {
63
+ context: CraftContext;
64
+ channel: unknown;
65
+ definition: RouteDefinition;
66
+ options: O;
67
+ register(handler: (message: unknown, headers?: ExchangeHeaders) => Promise<Exchange>): void;
68
+ }
69
+ interface ProcessingQueue<T = unknown> {
70
+ enqueue(message: T): Promise<Exchange>;
71
+ setHandler(handler: (message: T) => Promise<Exchange>): Promise<void> | void;
72
+ clear(): Promise<void> | void;
73
+ }
74
+ type ContextEventName = "contextStarting" | "contextStarted" | "contextStopping" | "contextStopped";
75
+ type RouteEventName = "routeRegistered" | "routeStarting" | "routeStarted" | "routeStopping" | "routeStopped";
76
+ type SystemEventName = "error";
77
+ type EventName = ContextEventName | RouteEventName | SystemEventName;
78
+ type EventDetailsMapping = {
79
+ contextStarting: Record<string, never>;
80
+ contextStarted: Record<string, never>;
81
+ contextStopping: {
82
+ reason?: unknown;
83
+ };
84
+ contextStopped: Record<string, never>;
85
+ routeRegistered: {
86
+ route: Route;
87
+ };
88
+ routeStarting: {
89
+ route: Route;
90
+ };
91
+ routeStarted: {
92
+ route: Route;
93
+ };
94
+ routeStopping: {
95
+ route: Route;
96
+ reason?: unknown;
97
+ exchange?: Exchange;
98
+ };
99
+ routeStopped: {
100
+ route: Route;
101
+ exchange?: Exchange;
102
+ };
103
+ error: {
104
+ error: unknown;
105
+ route?: Route;
106
+ exchange?: Exchange;
107
+ };
108
+ };
109
+ type EventPayload<K extends EventName> = {
110
+ ts: string;
111
+ context: CraftContext;
112
+ details: EventDetailsMapping[K];
113
+ };
114
+ type EventHandler<K extends EventName> = (payload: EventPayload<K>) => void | Promise<void>;
115
+
116
+ type CallableSource<T = unknown> = (context: CraftContext, handler: (message: T, headers?: ExchangeHeaders) => Promise<Exchange>, abortController: AbortController) => Promise<void> | void;
117
+ interface Source<T = unknown> extends Adapter {
118
+ subscribe: CallableSource<T>;
119
+ }
120
+
121
+ /**
122
+ * Defines the configuration for a route including its source, steps, and consumer.
123
+ *
124
+ * A route definition describes how data flows from a source through processing steps
125
+ * to one or more destinations.
126
+ *
127
+ * @template T The type of data produced by the source
128
+ */
129
+ type RouteDefinition<T = unknown> = {
130
+ /** Unique identifier for the route */
131
+ readonly id: string;
132
+ /** The source that provides data to the route */
133
+ readonly source: Source<T>;
134
+ /** Processing steps that transform, filter, or direct the data */
135
+ readonly steps: Step<Adapter>[];
136
+ /** Consumer configuration that determines how data is processed */
137
+ readonly consumer: {
138
+ /** The type of consumer to use */
139
+ type: ConsumerType<Consumer>;
140
+ /** Options for the consumer */
141
+ options: unknown;
142
+ };
143
+ };
144
+ /**
145
+ * Represents a runnable route that processes data.
146
+ *
147
+ * Routes handle the flow of data from a source through processing steps
148
+ * and can be started and stopped.
149
+ */
150
+ interface Route {
151
+ /** The context this route belongs to */
152
+ readonly context: CraftContext;
153
+ /** The route's configuration */
154
+ readonly definition: RouteDefinition;
155
+ /** Signal that indicates when the route has been aborted */
156
+ readonly signal: AbortSignal;
157
+ /** Logger for this route */
158
+ logger: Logger;
159
+ /**
160
+ * Start processing data on this route.
161
+ * @returns A promise that resolves when the route has started
162
+ */
163
+ start(): Promise<void>;
164
+ /**
165
+ * Stop processing data on this route.
166
+ */
167
+ stop(): void;
168
+ }
169
+ /**
170
+ * Default implementation of the Route interface.
171
+ *
172
+ * Handles the lifecycle of a route, managing the message flow from
173
+ * the source through the defined steps.
174
+ */
175
+ declare class DefaultRoute implements Route {
176
+ readonly context: CraftContext;
177
+ readonly definition: RouteDefinition;
178
+ /** Controls aborting the route's operations */
179
+ private abortController;
180
+ /** Logger for this route */
181
+ readonly logger: Logger;
182
+ /** Internal queue for passing messages between the source and consumer */
183
+ private messageChannel;
184
+ /** Processes messages from the message channel */
185
+ private consumer;
186
+ /**
187
+ * Create a new route instance.
188
+ *
189
+ * @param context The context this route belongs to
190
+ * @param definition The route's configuration
191
+ * @param abortController Optional controller for aborting the route
192
+ */
193
+ constructor(context: CraftContext, definition: RouteDefinition, abortController?: AbortController);
194
+ /**
195
+ * Get the abort signal for this route.
196
+ */
197
+ get signal(): AbortSignal;
198
+ /**
199
+ * Create a new exchange object from a message and optional headers.
200
+ *
201
+ * @param message The message data
202
+ * @param headers Optional headers to include
203
+ * @returns A new Exchange object
204
+ * @private
205
+ */
206
+ private buildExchange;
207
+ /**
208
+ * Start processing data on this route.
209
+ *
210
+ * This method:
211
+ * 1. Registers the consumer to process messages
212
+ * 2. Subscribes to the source to receive data
213
+ *
214
+ * @returns A promise that resolves when the route has started
215
+ * @throws {RouteCraftError} If the route has been aborted
216
+ */
217
+ start(): Promise<void>;
218
+ /**
219
+ * Stop processing data on this route.
220
+ *
221
+ * This method:
222
+ * 1. Unsubscribes from the internal processing queue
223
+ * 2. Aborts the route's controller
224
+ */
225
+ stop(): void;
226
+ /**
227
+ * Process an exchange through the route's steps.
228
+ *
229
+ * This is the main processing logic that:
230
+ * 1. Takes an initial exchange from the source
231
+ * 2. Processes it through each step in sequence
232
+ * 3. Handles errors that occur during processing
233
+ *
234
+ * @param exchange The initial exchange to process
235
+ * @returns A promise that resolves when processing is complete
236
+ * @private
237
+ */
238
+ private handler;
239
+ /**
240
+ * Check if the route has been aborted, and throw an error if it has.
241
+ *
242
+ * @throws {RouteCraftError} If the route has been aborted
243
+ * @private
244
+ */
245
+ private assertNotAborted;
246
+ /**
247
+ * Create a RouteCraftError from an operation error.
248
+ *
249
+ * @param operation The operation that caused the error
250
+ * @param code The error code
251
+ * @param error The original error
252
+ * @returns A formatted RouteCraftError
253
+ * @private
254
+ */
255
+ private processError;
256
+ }
257
+
258
+ /**
259
+ * Base store registry that can be extended by adapters
260
+ *
261
+ * @example
262
+ * ```typescript
263
+ * // Extend the store registry with channel adapter types
264
+ * declare module "@routecraft/routecraft" {
265
+ * interface StoreRegistry {
266
+ * "routecraft.adapter.channel.store": Map<string, import("./adapters/channel.ts").MessageChannel>;
267
+ * "routecraft.adapter.channel.config" Partial<ChannelAdapterOptions>;
268
+ * }
269
+ * }
270
+ * ```
271
+ */
272
+ interface StoreRegistry {
273
+ [key: `${string}.${string}.${string}`]: unknown;
274
+ }
275
+ /**
276
+ * Options with merged configuration support.
277
+ * This type is used for adapters that support both direct options and
278
+ * options that can be merged with context configuration.
279
+ */
280
+ type MergedOptions<T> = {
281
+ /** Direct options for configuration */
282
+ options: Partial<T>;
283
+ /**
284
+ * Function to merge options with context configuration
285
+ * @param context The CraftContext instance
286
+ * @returns Merged options
287
+ */
288
+ mergedOptions(context: CraftContext): T;
289
+ };
290
+ /**
291
+ * Configuration options for creating a CraftContext.
292
+ */
293
+ type CraftConfig = {
294
+ /** Initial values for the context store */
295
+ store?: Map<keyof StoreRegistry, StoreRegistry[keyof StoreRegistry]>;
296
+ /** Event handlers to register on context creation */
297
+ on?: Partial<Record<EventName, EventHandler<EventName> | EventHandler<EventName>[]>>;
298
+ };
299
+ /**
300
+ * The main context for running and managing routes.
301
+ *
302
+ * CraftContext is the central runtime environment that:
303
+ * - Manages the lifecycle of routes
304
+ * - Provides a storage system for adapters
305
+ * - Handles startup and shutdown of the application
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * // Create a context with routes and event handlers
310
+ * const context = new CraftContext({
311
+ * on: {
312
+ * contextStarting: async () => {
313
+ * console.log('Starting application');
314
+ * },
315
+ * contextStopping: async () => {
316
+ * console.log('Shutting down application');
317
+ * }
318
+ * }
319
+ * });
320
+ *
321
+ * // Register routes
322
+ * context.registerRoutes(myRoute1, myRoute2);
323
+ *
324
+ * // Start processing routes
325
+ * await context.start();
326
+ *
327
+ * // Later, stop all routes
328
+ * await context.stop();
329
+ * ```
330
+ */
331
+ declare class CraftContext {
332
+ /** Unique identifier for this context instance */
333
+ readonly contextId: string;
334
+ /** Routes registered with this context */
335
+ private routes;
336
+ /** Abort controllers for each route */
337
+ private controllers;
338
+ /** Storage for adapter configuration and state */
339
+ private store;
340
+ /** Logger for this context */
341
+ readonly logger: Logger;
342
+ /** Registered event handlers */
343
+ private readonly handlers;
344
+ /**
345
+ * Create a new CraftContext instance.
346
+ *
347
+ * @param config Optional configuration for the context
348
+ */
349
+ constructor(config?: CraftConfig);
350
+ /**
351
+ * Subscribe to lifecycle and system events.
352
+ *
353
+ * Handlers receive payloads with shape { ts, context, details }.
354
+ */
355
+ on<K extends EventName>(event: K, handler: EventHandler<K>): () => void;
356
+ /**
357
+ * Emit an event to registered handlers. Public for internal use by routes/adapters.
358
+ */
359
+ emit<K extends EventName>(event: K, details: EventPayload<K>["details"]): void;
360
+ /**
361
+ * Register routes with this context.
362
+ *
363
+ * @param definitions Route definitions to register
364
+ * @throws {RouteCraftError} If there are duplicate route IDs or invalid route definitions
365
+ *
366
+ * @example
367
+ * ```typescript
368
+ * // Register a single route
369
+ * context.registerRoutes(myRoute);
370
+ *
371
+ * // Register multiple routes
372
+ * context.registerRoutes(route1, route2, route3);
373
+ * ```
374
+ */
375
+ registerRoutes(...definitions: RouteDefinition[]): void;
376
+ /**
377
+ * Get all routes registered with this context.
378
+ *
379
+ * @returns Array of routes
380
+ */
381
+ getRoutes(): Route[];
382
+ /**
383
+ * Get a value from the context store.
384
+ *
385
+ * @template K Store key type
386
+ * @param key The store key to retrieve
387
+ * @returns The stored value or undefined if not found
388
+ *
389
+ * @example
390
+ * ```typescript
391
+ * // Get channel store
392
+ * const channelStore = context.getStore('routecraft.adapter.channel.store');
393
+ * ```
394
+ */
395
+ getStore<K extends keyof StoreRegistry>(key: K): StoreRegistry[K] | undefined;
396
+ /**
397
+ * Set a value in the context store.
398
+ *
399
+ * @template K Store key type
400
+ * @param key The store key
401
+ * @param value The value to store
402
+ *
403
+ * @example
404
+ * ```typescript
405
+ * // Set channel store
406
+ * context.setStore('routecraft.adapter.channel.store', new Map());
407
+ * ```
408
+ */
409
+ setStore<K extends keyof StoreRegistry>(key: K, value: StoreRegistry[K]): void;
410
+ /**
411
+ * Find a route by its ID.
412
+ *
413
+ * @param id The route ID to find
414
+ * @returns The matching route or undefined if not found
415
+ */
416
+ getRouteById(id: string): Route | undefined;
417
+ /**
418
+ * Start all routes registered with this context.
419
+ *
420
+ * This will:
421
+ * 1. Run the onStartup handler if defined
422
+ * 2. Start all routes in parallel
423
+ * 3. Wait for all routes to complete if they're not indefinite
424
+ * 4. Automatically stop the context if all routes complete
425
+ *
426
+ * @returns A promise that resolves when all routes have started
427
+ * @throws If any route fails to start
428
+ *
429
+ * @example
430
+ * ```typescript
431
+ * try {
432
+ * await context.start();
433
+ * console.log('All routes started successfully');
434
+ * } catch (error) {
435
+ * console.error('Failed to start routes:', error);
436
+ * }
437
+ * ```
438
+ */
439
+ start(): Promise<void>;
440
+ /**
441
+ * Stop all routes and shut down the context.
442
+ *
443
+ * This will:
444
+ * 1. Abort all route controllers
445
+ * 2. Run the onShutdown handler if defined
446
+ *
447
+ * @returns A promise that resolves when all shutdown operations complete
448
+ *
449
+ * @example
450
+ * ```typescript
451
+ * // Handle shutdown signals
452
+ * process.on('SIGINT', async () => {
453
+ * console.log('Shutting down...');
454
+ * await context.stop();
455
+ * process.exit(0);
456
+ * });
457
+ * ```
458
+ */
459
+ stop(): Promise<void>;
460
+ }
461
+
462
+ /**
463
+ * Types of operations that can be performed on an exchange.
464
+ * These values are used in exchange headers to track the current operation.
465
+ */
466
+ declare enum OperationType {
467
+ /** The exchange was created from a source */
468
+ FROM = "from",
469
+ /** The exchange was processed by a processor */
470
+ PROCESS = "process",
471
+ /** The exchange was sent to a destination */
472
+ TO = "to",
473
+ /** The exchange was split into multiple exchanges */
474
+ SPLIT = "split",
475
+ /** The exchange was aggregated from multiple exchanges */
476
+ AGGREGATE = "aggregate",
477
+ /** Modify the body of the exchange */
478
+ TRANSFORM = "transform",
479
+ /** Tap an exchange without modifying it */
480
+ TAP = "tap",
481
+ /** Filter an exchange based on a condition and reject the message if the condition is not met */
482
+ FILTER = "filter",
483
+ /** Validate the exchange against a schema and reject the message if the schema is not met */
484
+ VALIDATE = "validate",
485
+ /** Enrich the exchange with data from another exchange */
486
+ ENRICH = "enrich",
487
+ /** Set or override a header on the exchange */
488
+ HEADER = "header"
489
+ }
490
+ /**
491
+ * Standard header keys used in exchanges.
492
+ * These keys provide metadata and context for processing exchanges.
493
+ */
494
+ declare enum HeadersKeys {
495
+ /** The operation type (from, process, to) */
496
+ OPERATION = "routecraft.operation",
497
+ /** The route id */
498
+ ROUTE_ID = "routecraft.route",
499
+ /** The correlation id */
500
+ CORRELATION_ID = "routecraft.correlation_id",
501
+ /** The hierarchy of split groups this exchange belongs to */
502
+ SPLIT_HIERARCHY = "routecraft.split_hierarchy",
503
+ /** The exact timestamp when the timer fired, in ISO 8601 format */
504
+ TIMER_TIME = "routecraft.timer.time",
505
+ /** The timestamp when the exchange was created, in ISO 8601 format */
506
+ TIMER_FIRED_TIME = "routecraft.timer.firedTime",
507
+ /** The period in milliseconds between timer firings */
508
+ TIMER_PERIOD_MS = "routecraft.timer.periodMs",
509
+ /** The number of times the timer has fired */
510
+ TIMER_COUNTER = "routecraft.timer.counter",
511
+ /** The next timestamp when the timer will fire, in ISO 8601 format */
512
+ TIMER_NEXT_RUN = "routecraft.timer.nextRun"
513
+ }
514
+ /**
515
+ * Standard headers used by the Routecraft framework.
516
+ * These headers provide critical metadata for processing exchanges.
517
+ */
518
+ interface RouteCraftHeaders {
519
+ /** The current operation being performed */
520
+ [HeadersKeys.OPERATION]: OperationType;
521
+ /** The ID of the route processing this exchange */
522
+ [HeadersKeys.ROUTE_ID]: string;
523
+ /** Unique identifier for correlating related exchanges */
524
+ [HeadersKeys.CORRELATION_ID]: string;
525
+ /** Hierarchy path for split operations */
526
+ [HeadersKeys.SPLIT_HIERARCHY]?: string[];
527
+ /** Timer-specific headers */
528
+ [HeadersKeys.TIMER_TIME]?: string;
529
+ [HeadersKeys.TIMER_FIRED_TIME]?: string;
530
+ [HeadersKeys.TIMER_PERIOD_MS]?: number;
531
+ [HeadersKeys.TIMER_COUNTER]?: number;
532
+ [HeadersKeys.TIMER_NEXT_RUN]?: string;
533
+ }
534
+ /**
535
+ * Possible types for header values.
536
+ */
537
+ type HeaderValue = string | number | boolean | undefined | string[];
538
+ /**
539
+ * Complete set of headers for an exchange.
540
+ * Includes both standard Routecraft headers and custom headers.
541
+ */
542
+ type ExchangeHeaders = Partial<RouteCraftHeaders> & Record<string, HeaderValue>;
543
+ /**
544
+ * Represents a message being processed through a route.
545
+ *
546
+ * An exchange encapsulates:
547
+ * - The data being processed (body)
548
+ * - Metadata about the processing (headers)
549
+ * - A unique identifier
550
+ * - Logging capabilities
551
+ *
552
+ * @template T The type of data in the body
553
+ */
554
+ type Exchange<T = unknown> = {
555
+ /** Unique identifier for this exchange */
556
+ readonly id: string;
557
+ /** Headers containing metadata */
558
+ readonly headers: ExchangeHeaders;
559
+ /** The data being processed */
560
+ body: T;
561
+ /** Logger for this exchange */
562
+ logger: Logger;
563
+ };
564
+ /**
565
+ * Default implementation of the Exchange interface.
566
+ *
567
+ * Provides standard exchange functionality with automatic
568
+ * ID generation and header initialization.
569
+ *
570
+ * @template T The type of data in the body
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // Create a simple exchange with a string body
575
+ * const exchange = new DefaultExchange<string>(context, {
576
+ * body: "Hello, World!"
577
+ * });
578
+ *
579
+ * // Access exchange properties
580
+ * console.log(exchange.id); // Unique UUID
581
+ * console.log(exchange.body); // "Hello, World!"
582
+ * console.log(exchange.headers); // Headers object with standard fields
583
+ * ```
584
+ */
585
+ declare class DefaultExchange<T = unknown> implements Exchange<T> {
586
+ readonly context: CraftContext;
587
+ /** Unique identifier for this exchange */
588
+ readonly id: string;
589
+ /** Headers containing metadata */
590
+ readonly headers: ExchangeHeaders;
591
+ /** The data being processed */
592
+ body: T;
593
+ /** Logger for this exchange */
594
+ readonly logger: Logger;
595
+ /**
596
+ * Create a new exchange.
597
+ *
598
+ * @param context The CraftContext this exchange belongs to
599
+ * @param options Optional configuration for the exchange
600
+ */
601
+ constructor(context: CraftContext, options?: Partial<Exchange<T>>);
602
+ }
603
+
604
+ /**
605
+ * Processor: mutate or derive a new Exchange from the current one.
606
+ * - May change body, headers, and type
607
+ * - Prefer pure logic; avoid side effects (use `.to(...)` for IO)
608
+ * - Use when you need access to headers or want to replace the whole exchange
609
+ */
610
+ type CallableProcessor<T = unknown, R = T> = (exchange: Exchange<T>) => Promise<Exchange<R>> | Exchange<R>;
611
+ interface Processor<T = unknown, R = T> extends Adapter {
612
+ process: CallableProcessor<T, R>;
613
+ }
614
+
615
+ /**
616
+ * To (Destination): side effects/output only.
617
+ * - Sends or persists the current exchange
618
+ * - Must not modify the message; downstream continues unchanged
619
+ * - Use for IO boundaries (DB writes, HTTP emits, queues)
620
+ */
621
+ type CallableDestination<T = unknown> = (exchange: Exchange<T>) => Promise<void> | void;
622
+ interface Destination<T = unknown> extends Adapter {
623
+ send: CallableDestination<T>;
624
+ }
625
+
626
+ type CallableSplitter<T = unknown, R = unknown> = (body: T) => Promise<R[]> | R[];
627
+ interface Splitter<T = unknown, R = unknown> extends Adapter {
628
+ split: CallableSplitter<T, R>;
629
+ }
630
+
631
+ type CallableAggregator<T = unknown, R = T> = (exchanges: Exchange<T>[]) => Promise<Exchange<R>> | Exchange<R>;
632
+ interface Aggregator<T = unknown, R = unknown> extends Adapter {
633
+ aggregate: CallableAggregator<T, R>;
634
+ }
635
+
636
+ /**
637
+ * Transform: body-only pure conversion.
638
+ * - Returns a new body; headers and metadata remain unchanged
639
+ * - Prefer this for simple mapping/scalar conversions
640
+ * - Use `.process` instead if you need to modify headers or other Exchange fields
641
+ */
642
+ type CallableTransformer<T = unknown, R = T> = (message: T) => Promise<R> | R;
643
+ interface Transformer<T = unknown, R = T> extends Adapter {
644
+ transform: CallableTransformer<T, R>;
645
+ }
646
+
647
+ type CallableTap<T = unknown> = (exchange: Exchange<T>) => Promise<void> | void;
648
+ interface Tap<T = unknown> extends Adapter {
649
+ tap: CallableTap<T>;
650
+ }
651
+
652
+ type CallableFilter<T = unknown> = (exchange: Exchange<T>) => Promise<boolean> | boolean;
653
+ interface Filter<T = unknown> extends Adapter {
654
+ filter: CallableFilter<T>;
655
+ }
656
+
657
+ /**
658
+ * Function that produces enrichment data based on the original exchange.
659
+ * Returns only the enrichment payload (body) which will be combined with the
660
+ * original exchange by the aggregator.
661
+ */
662
+ type CallableEnricher<T = unknown, R = unknown> = (exchange: Exchange<T>) => Promise<R> | R;
663
+ /**
664
+ * Enricher: produce data to merge into the existing exchange.
665
+ * - Does not return a new Exchange; only the enrichment payload
666
+ * - Combine with default or custom aggregator in `.enrich(adapter, aggregator)`
667
+ */
668
+ interface Enricher<T = unknown, R = unknown> extends Adapter {
669
+ enrich: CallableEnricher<T, R>;
670
+ adapterId: string;
671
+ }
672
+ /**
673
+ * Function that aggregates the original exchange with the enrichment data
674
+ * Similar to CallableAggregator but specifically for the enrich operation
675
+ */
676
+ type EnrichAggregator<T = unknown, R = unknown> = (original: Exchange<T>, enrichmentData: R) => Promise<Exchange<T>> | Exchange<T>;
677
+ /**
678
+ * Default aggregator that merges the enrichment data with the original exchange body.
679
+ *
680
+ * This aggregator:
681
+ * 1. Converts the original body to an object if it's not already one (using {value: originalBody})
682
+ * 2. Converts the enrichment data to an object if it's not already one (using {value: enrichmentData})
683
+ * 3. Merges these objects using spread syntax ({...originalBody, ...enrichmentObject})
684
+ *
685
+ * Note: If both the original body and enrichment data have a 'value' property,
686
+ * the enrichment data's 'value' will overwrite the original's 'value'.
687
+ */
688
+ declare const defaultEnrichAggregator: <T = unknown, R = unknown>(original: Exchange<T>, enrichmentData: R) => Exchange<T>;
689
+
690
+ /**
691
+ * Builder for creating a RouteCraft context with routes and configuration.
692
+ *
693
+ * This builder provides a fluent API for configuring and creating a CraftContext
694
+ * with routes, startup/shutdown handlers, and initial store values.
695
+ *
696
+ * @example
697
+ * ```typescript
698
+ * // Create a context with routes and handlers
699
+ * const context = new ContextBuilder()
700
+ * .with({ store: new Map() })
701
+ * .on('contextStarting', ({ ts }) => console.log('Starting at', ts))
702
+ * .store('routecraft.adapter.channel.store', new Map())
703
+ * .routes(routes1)
704
+ * .routes([routes2, routes3])
705
+ * .build();
706
+ *
707
+ * // Start the context to begin processing
708
+ * await context.start();
709
+ * ```
710
+ */
711
+ declare class ContextBuilder {
712
+ protected config?: CraftConfig;
713
+ protected definitions: RouteDefinition[];
714
+ protected initialStores: Map<`${string}.${string}.${string}`, unknown>;
715
+ protected eventHandlers: Map<EventName, Set<EventHandler<EventName>>>;
716
+ constructor();
717
+ /**
718
+ * Configure the context with the provided config object.
719
+ *
720
+ * @param config The configuration object for the context
721
+ * @returns This builder instance for method chaining
722
+ */
723
+ with(config: CraftConfig): this;
724
+ /**
725
+ * Register an event listener to be attached to the built context.
726
+ */
727
+ on<K extends EventName>(event: K, handler: EventHandler<K>): this;
728
+ /**
729
+ * Add an initial value to the context store.
730
+ *
731
+ * @template K The store key type
732
+ * @param key The store key
733
+ * @param value The initial value for the store
734
+ * @returns This builder instance for method chaining
735
+ *
736
+ * @example
737
+ * ```typescript
738
+ * // Add an initial channel store
739
+ * builder.store('routecraft.adapter.channel.store', new Map());
740
+ * ```
741
+ */
742
+ store<K extends keyof StoreRegistry>(key: K, value: StoreRegistry[K]): this;
743
+ /**
744
+ * Add routes to the context.
745
+ *
746
+ * Routes can be added as individual RouteDefinitions, RouteBuilders, or arrays of either.
747
+ *
748
+ * @param routes Individual or array of route definitions/builders to add
749
+ * @returns This builder instance for method chaining
750
+ *
751
+ * @example
752
+ * ```typescript
753
+ * // Add a single route
754
+ * builder.routes(myRoute);
755
+ *
756
+ * // Add multiple routes
757
+ * builder.routes([route1, route2, route3]);
758
+ *
759
+ * // Add a route builder
760
+ * builder.routes(
761
+ * craft()
762
+ * .from(simple("hello"))
763
+ * .to(log())
764
+ * );
765
+ * ```
766
+ */
767
+ routes(routes: RouteDefinition[] | RouteBuilder<unknown>[] | RouteDefinition | RouteBuilder<unknown>): this;
768
+ /**
769
+ * Build and return a configured CraftContext instance.
770
+ *
771
+ * This finalizes the configuration and creates a ready-to-use context
772
+ * with all the configured routes, handlers, and store values.
773
+ *
774
+ * @returns A new CraftContext instance
775
+ */
776
+ build(): CraftContext;
777
+ }
778
+ /**
779
+ * Options for configuring a route.
780
+ */
781
+ type RouteOptions = Partial<Pick<RouteDefinition, "consumer">> & {
782
+ /**
783
+ * Unique identifier for the route.
784
+ */
785
+ id: string;
786
+ };
787
+ /**
788
+ * Builder for creating route definitions with a fluent API.
789
+ *
790
+ * This builder provides methods for defining the steps in a route,
791
+ * including sources, transformations, filters, destinations, and more.
792
+ *
793
+ * The type parameter tracks the data type flowing through the route
794
+ * at each step, providing type safety throughout the route definition.
795
+ *
796
+ * @template Current The type of data currently flowing through the route
797
+ *
798
+ * @example
799
+ * ```typescript
800
+ * // Create a simple route that processes a string
801
+ * const route = craft()
802
+ * .from(simple("Hello, World!"))
803
+ * .transform(msg => msg.toUpperCase())
804
+ * .to(log())
805
+ * ```
806
+ */
807
+ declare class RouteBuilder<Current = unknown> {
808
+ protected currentRoute?: RouteDefinition;
809
+ protected routes: RouteDefinition[];
810
+ protected pendingOptions?: {
811
+ id?: string;
812
+ consumer?: {
813
+ type: ConsumerType<Consumer>;
814
+ options?: unknown;
815
+ };
816
+ } | undefined;
817
+ constructor();
818
+ /**
819
+ * Internal method to create a new RouteBuilder with an updated type parameter.
820
+ * This is used to propagate type information through the method chain.
821
+ *
822
+ * @template T The new type to use for the RouteBuilder
823
+ * @returns A new RouteBuilder instance with the updated type
824
+ * @private
825
+ */
826
+ private withType;
827
+ /**
828
+ * Set the route id for the next route to be created.
829
+ * This stages the id and does not affect the current route if one exists.
830
+ */
831
+ id(id: string): this;
832
+ /**
833
+ * Configure batch processing for the next route to be created.
834
+ * This stages the batch consumer and does not affect the current route if one exists.
835
+ */
836
+ batch(options?: {
837
+ size?: number;
838
+ flushIntervalMs?: number;
839
+ }): this;
840
+ /**
841
+ * Define the source of data for this route.
842
+ * This is typically the first step in defining a route.
843
+ *
844
+ * @template T The type of data produced by the source
845
+ * @param source A source adapter or function
846
+ * @returns A RouteBuilder with the specified type T
847
+ * @example
848
+ * // Simple source with inferred type
849
+ * .from<string[]>(httpServer({ path: '/api/data' }))
850
+ *
851
+ * // Source with callable function
852
+ * .from<User[]>(async () => {
853
+ * const response = await fetch('https://api.example.com/users');
854
+ * return response.json();
855
+ * })
856
+ */
857
+ from<T>(source: Source<T> | CallableSource<T>): RouteBuilder<T>;
858
+ /**
859
+ * Internal method to ensure a source has been defined for the current route.
860
+ * Throws an error if no source has been defined.
861
+ *
862
+ * @returns The current route definition
863
+ * @throws Error if no source has been defined
864
+ * @private
865
+ */
866
+ private requireSource;
867
+ /**
868
+ * Internal method to add a step to the current route.
869
+ * This is used by the public methods to build up the route definition.
870
+ *
871
+ * @template T The type of adapter used by the step
872
+ * @param step The step definition to add
873
+ * @returns The current RouteBuilder instance
874
+ * @private
875
+ */
876
+ private addStep;
877
+ /**
878
+ * Process the data with a custom function.
879
+ *
880
+ * @template Return The resulting type after processing (defaults to Current if not specified)
881
+ * @param processor A function that transforms the current exchange to a new exchange with the Return
882
+ * @returns A RouteBuilder with the new type Return
883
+ * @example
884
+ * // Transform string data to number
885
+ * .process<number>((exchange) => {
886
+ * return { ...exchange, body: parseInt(exchange.body) };
887
+ * })
888
+ */
889
+ process<Return = Current>(processor: Processor<Current, Return> | CallableProcessor<Current, Return>): RouteBuilder<Return>;
890
+ /**
891
+ * Send the processed data to a destination.
892
+ * This is typically the final step in a route.
893
+ * The type remains the same after this operation.
894
+ *
895
+ * @param destination A function or adapter that consumes the data
896
+ * @returns A RouteBuilder with the same type
897
+ * @example
898
+ * // Send data to a database
899
+ * .to(async ({ body }) => {
900
+ * await db.users.insert(body);
901
+ * })
902
+ *
903
+ * // Send to a predefined destination
904
+ * .to(kafkaProducer({ topic: 'processed-data' }))
905
+ */
906
+ to(destination: Destination<Current> | CallableDestination<Current>): RouteBuilder<Current>;
907
+ /**
908
+ * Split an array into individual items for processing.
909
+ * Each item becomes a separate exchange with a new UUID and copied headers.
910
+ * If no splitter is provided and the current data is an array, it will automatically
911
+ * split the array into individual items.
912
+ *
913
+ * Similar to Apache Camel's Splitter EIP: accepts body, returns array of body items.
914
+ * The framework automatically creates new exchanges for each item.
915
+ *
916
+ * @template ItemType The type of items in the array (inferred from array if not specified)
917
+ * @param splitter Optional function that receives the body and returns an array of items
918
+ * @returns A RouteBuilder with the item type
919
+ * @example
920
+ * // Automatically split an array of numbers
921
+ * .from<number[]>(source)
922
+ * .split() // ItemType is inferred as number
923
+ *
924
+ * // Custom splitting logic - extract nested array
925
+ * .from(source)
926
+ * .split<User>((body) => body.users)
927
+ *
928
+ * // Split a string by delimiter
929
+ * .split<string>((body) => body.split(","))
930
+ */
931
+ split<ItemType = Current extends Array<infer U> ? U : never>(splitter?: Splitter<Current, ItemType> | CallableSplitter<Current, ItemType>): RouteBuilder<ItemType>;
932
+ /**
933
+ * Aggregate multiple items into a single result.
934
+ * This is often used after a split operation to collect and combine the results.
935
+ *
936
+ * @template ResultType The resulting type after aggregation
937
+ * @param aggregator A function that combines multiple items into a single result
938
+ * @returns A RouteBuilder with the new aggregated type
939
+ * @example
940
+ * // Aggregate an array of numbers into a sum
941
+ * .split() // Working with individual numbers
942
+ * .process((exchange) => ({ ...exchange, body: exchange.body * 2 })) // Double each number
943
+ * .aggregate<number>((exchanges) => {
944
+ * const sum = exchanges.reduce((acc, ex) => acc + ex.body, 0);
945
+ * return { body: sum, headers: exchanges[0].headers };
946
+ * })
947
+ */
948
+ aggregate<ResultType>(aggregator: Aggregator<Current, ResultType> | CallableAggregator<Current, ResultType>): RouteBuilder<ResultType>;
949
+ /**
950
+ * Transform the current data to a new type using a transformer function.
951
+ * Unlike process, this operates only on the body of the exchange, not the entire exchange.
952
+ *
953
+ * @template Return The resulting type after transformation
954
+ * @param transformer A function that transforms the current body to a new body of type Return
955
+ * @returns A RouteBuilder with the new type Return
956
+ * @example
957
+ * // Transform a string to an object
958
+ * .transform<{ value: string }>((str) => ({ value: str }))
959
+ */
960
+ transform<Return>(transformer: Transformer<Current, Return> | CallableTransformer<Current, Return>): RouteBuilder<Return>;
961
+ /**
962
+ * Set or override a header on the current exchange.
963
+ * The body type remains unchanged.
964
+ *
965
+ * @param key Header key to set
966
+ * @param valueOrFn A static value or a function returning the value from exchange data
967
+ * @returns A RouteBuilder with the same type
968
+ * @example
969
+ * // Static value
970
+ * .header('x-env', 'prod')
971
+ *
972
+ * // Derived from body
973
+ * .header('user.id', (exchange) => exchange.body.id)
974
+ *
975
+ * // Derived from headers
976
+ * .header('correlation', (exchange) => exchange.headers['x-request-id'])
977
+ */
978
+ header(key: string, valueOrFn: HeaderValue | ((exchange: Exchange<Current>) => HeaderValue | Promise<HeaderValue>)): RouteBuilder<Current>;
979
+ /**
980
+ * Map fields from the current data to create a new object of a specified type.
981
+ * This is a specialized transformer that creates a new object by mapping fields
982
+ * from the source object.
983
+ *
984
+ * @template Return The resulting type after mapping
985
+ * @param fieldMappings An object where keys are field names in the output type and values are
986
+ * functions that extract the corresponding values from the source
987
+ * @returns A RouteBuilder with the new type Return
988
+ * @example
989
+ * // Map from API response to database model
990
+ * .map<DbUser>({
991
+ * id: (apiUser) => apiUser.userId,
992
+ * name: (apiUser) => apiUser.fullName,
993
+ * email: (apiUser) => apiUser.emailAddress
994
+ * })
995
+ */
996
+ map<Return>(fieldMappings: Record<keyof Return, (src: Current) => Return[keyof Return]>): RouteBuilder<Return>;
997
+ /**
998
+ * Execute a side effect without changing the data.
999
+ * This is useful for logging, metrics, or other operations that don't modify the data.
1000
+ * The type remains the same after tapping.
1001
+ *
1002
+ * @param tap A function that performs a side effect
1003
+ * @returns A RouteBuilder with the same type
1004
+ * @example
1005
+ * // Log the current data
1006
+ * .tap((exchange) => console.log('Processing:', exchange.body))
1007
+ *
1008
+ * // Send metrics
1009
+ * .tap((exchange) => {
1010
+ * metrics.increment('items_processed');
1011
+ * metrics.gauge('item_size', JSON.stringify(exchange.body).length);
1012
+ * })
1013
+ */
1014
+ tap(tap: Tap<Current> | CallableTap<Current>): RouteBuilder<Current>;
1015
+ /**
1016
+ * Filter data based on a predicate function.
1017
+ * Exchanges that don't match the predicate will be dropped.
1018
+ *
1019
+ * @param filter A function that returns true to keep the exchange, false to drop it
1020
+ * @returns A RouteBuilder with the same type
1021
+ * @example
1022
+ * // Keep only numbers greater than 10
1023
+ * .filter((num) => num > 10)
1024
+ *
1025
+ * // Filter based on a complex condition
1026
+ * .filter((user) => user.age >= 18 && user.status === 'active')
1027
+ */
1028
+ filter(filter: Filter<Current> | CallableFilter<Current>): RouteBuilder<Current>;
1029
+ /**
1030
+ * Validate data against a schema.
1031
+ * Throws an error if validation fails.
1032
+ *
1033
+ * @param schema A JSON schema to validate against
1034
+ * @returns A RouteBuilder with the same type
1035
+ * @example
1036
+ * // Validate with JSON schema
1037
+ * .validate({
1038
+ * type: 'object',
1039
+ * properties: {
1040
+ * name: { type: 'string' },
1041
+ * age: { type: 'number', minimum: 0 }
1042
+ * },
1043
+ * required: ['name', 'age']
1044
+ * })
1045
+ */
1046
+ validate(schema: StandardSchemaV1): RouteBuilder<Current>;
1047
+ /**
1048
+ * Enrich the current data with additional information.
1049
+ * This is useful for adding context or fetching related data.
1050
+ *
1051
+ * @template R The resulting type after enrichment (defaults to Current if not specified)
1052
+ * @param enricher Function that returns additional data to be merged
1053
+ * @param aggregator Optional function to control how data is combined
1054
+ * @returns A RouteBuilder with the combined type
1055
+ * @example
1056
+ * // Add user details from an API
1057
+ * .enrich<User & { profile: Profile }>(async (user) => {
1058
+ * const details = await fetchUserDetails(user.id);
1059
+ * return details;
1060
+ * })
1061
+ *
1062
+ * // Custom aggregation strategy
1063
+ * .enrich<CustomType>(
1064
+ * async (exchange) => ({ extraData: "value" }),
1065
+ * (original, enrichmentData) => ({
1066
+ * ...original,
1067
+ * body: customMergeFunction(original.body, enrichmentData)
1068
+ * })
1069
+ * )
1070
+ */
1071
+ enrich<R = Current>(enricher: Enricher<Current, Partial<R>> | CallableEnricher<Current, Partial<R>>, aggregator?: EnrichAggregator<Current, Partial<R>>): RouteBuilder<R>;
1072
+ /**
1073
+ * Finalize the route definition and return it.
1074
+ * This method should be called after all steps have been defined.
1075
+ *
1076
+ * @returns An array of RouteDefinition objects
1077
+ * @example
1078
+ * // Define a complete route and build it
1079
+ * const route = craft()
1080
+ * .from<string[]>(source)
1081
+ * .split()
1082
+ * .process((exchange) => ({ ...exchange, body: exchange.body.toUpperCase() }))
1083
+ * .to(destination)
1084
+ *
1085
+ * // Add the route to a context
1086
+ * context()
1087
+ * .routes(route)
1088
+ * .build();
1089
+ */
1090
+ build(): RouteDefinition[];
1091
+ }
1092
+
1093
+ type RCCode = "RC1001" | "RC1002" | "RC2001" | "RC2002" | "RC3001" | "RC3002" | "RC5001" | "RC5002" | "RC5003" | "RC5004" | "RC5005" | "RC5006" | "RC5007" | "RC5008" | "RC5009" | "RC9901";
1094
+ type RCMeta = {
1095
+ category: "Definition" | "DSL" | "Lifecycle" | "Adapter" | "Runtime";
1096
+ message: string;
1097
+ suggestion?: string;
1098
+ docs: string;
1099
+ };
1100
+ declare const RC: Record<RCCode, RCMeta>;
1101
+ declare class RouteCraftError extends Error {
1102
+ readonly rc: RCCode;
1103
+ readonly meta: RCMeta;
1104
+ constructor(rc: RCCode, meta: RCMeta, cause?: unknown);
1105
+ toString(): string;
1106
+ static parse(cause: unknown): {
1107
+ message: string;
1108
+ error: Error;
1109
+ };
1110
+ }
1111
+ declare function error(rc: RCCode, cause?: unknown, overrides?: Partial<Pick<RCMeta, "message" | "suggestion" | "docs">>): RouteCraftError;
1112
+
1113
+ declare class SimpleConsumer implements Consumer<never> {
1114
+ readonly context: CraftContext;
1115
+ readonly definition: RouteDefinition;
1116
+ readonly channel: ProcessingQueue<Message>;
1117
+ readonly options: never;
1118
+ constructor(context: CraftContext, definition: RouteDefinition, channel: ProcessingQueue<Message>, options: never);
1119
+ register(handler: (message: unknown, headers?: ExchangeHeaders) => Promise<Exchange>): Promise<void>;
1120
+ }
1121
+
1122
+ type BatchOptions = {
1123
+ /**
1124
+ * The size of the batch.
1125
+ */
1126
+ size?: number;
1127
+ /**
1128
+ * The timeout between batches in milliseconds.
1129
+ */
1130
+ time?: number;
1131
+ /**
1132
+ * The function to merge the produced messages.
1133
+ */
1134
+ merge?: (exchanges: {
1135
+ message: unknown;
1136
+ headers?: ExchangeHeaders;
1137
+ }[]) => {
1138
+ message: unknown;
1139
+ headers?: ExchangeHeaders;
1140
+ };
1141
+ };
1142
+ declare class BatchConsumer implements Consumer<BatchOptions> {
1143
+ readonly context: CraftContext;
1144
+ readonly definition: RouteDefinition;
1145
+ readonly channel: ProcessingQueue<Message>;
1146
+ readonly options: BatchOptions;
1147
+ constructor(context: CraftContext, definition: RouteDefinition, channel: ProcessingQueue<Message>, options: BatchOptions);
1148
+ register(handler: (message: unknown, headers?: ExchangeHeaders) => Promise<Exchange>): Promise<void>;
1149
+ }
1150
+
1151
+ declare class SimpleAdapter<T = unknown> implements Source<T> {
1152
+ private producer;
1153
+ readonly adapterId = "routecraft.adapter.simple";
1154
+ constructor(producer: () => T | Promise<T>);
1155
+ subscribe(context: CraftContext, handler: (message: T, headers?: ExchangeHeaders) => Promise<Exchange>, abortController: AbortController): Promise<void>;
1156
+ }
1157
+
1158
+ declare class NoopAdapter<T = unknown> implements Destination<T> {
1159
+ readonly adapterId = "routecraft.adapter.noop";
1160
+ send(exchange: Exchange<T>): Promise<void>;
1161
+ }
1162
+
1163
+ declare class LogAdapter<T = unknown> implements Destination<T>, Tap<T> {
1164
+ private readonly formatter?;
1165
+ readonly adapterId = "routecraft.adapter.log";
1166
+ constructor(formatter?: ((exchange: Exchange<T>) => unknown) | undefined);
1167
+ send(exchange: Exchange<T>): Promise<void>;
1168
+ tap(exchange: Exchange<T>): Promise<void>;
1169
+ private baseExchange;
1170
+ }
1171
+
1172
+ type DirectChannelType<T extends DirectChannel> = new (endpoint: string) => T;
1173
+ /**
1174
+ * DirectChannel interface for synchronous inter-route communication.
1175
+ *
1176
+ * Implements Apache Camel's direct: component semantics:
1177
+ * - Single consumer per endpoint (last subscriber wins)
1178
+ * - Synchronous blocking behavior (sender waits for response)
1179
+ * - Point-to-point messaging (not pub/sub)
1180
+ */
1181
+ interface DirectChannel<T = unknown> {
1182
+ send(endpoint: string, message: T): Promise<T>;
1183
+ subscribe(context: CraftContext, endpoint: string, handler: (message: T) => Promise<T>): Promise<void>;
1184
+ unsubscribe(context: CraftContext, endpoint: string): Promise<void>;
1185
+ }
1186
+ interface DirectAdapterOptions {
1187
+ channelType?: DirectChannelType<DirectChannel>;
1188
+ }
1189
+ declare module "@routecraft/routecraft" {
1190
+ interface StoreRegistry {
1191
+ [DirectAdapter.ADAPTER_DIRECT_STORE]: Map<string, DirectChannel<Exchange>>;
1192
+ [DirectAdapter.ADAPTER_DIRECT_OPTIONS]: Partial<DirectAdapterOptions>;
1193
+ }
1194
+ }
1195
+ declare class DirectAdapter<T = unknown> implements Source<T>, Destination<T>, MergedOptions<DirectAdapterOptions> {
1196
+ options: Partial<DirectAdapterOptions>;
1197
+ readonly adapterId = "routecraft.adapter.direct";
1198
+ static readonly ADAPTER_DIRECT_STORE: "routecraft.adapter.direct.store";
1199
+ static readonly ADAPTER_DIRECT_OPTIONS: "routecraft.adapter.direct.options";
1200
+ private rawEndpoint;
1201
+ constructor(rawEndpoint: string, options?: Partial<DirectAdapterOptions>);
1202
+ private get sanitizedEndpoint();
1203
+ subscribe(context: CraftContext, handler: (message: T, headers?: ExchangeHeaders) => Promise<Exchange>, abortController: AbortController): Promise<void>;
1204
+ private directChannel;
1205
+ send(exchange: Exchange<T>): Promise<void>;
1206
+ mergedOptions(context: CraftContext): DirectAdapterOptions;
1207
+ }
1208
+
1209
+ interface TimerOptions {
1210
+ /**
1211
+ * Time between executions in milliseconds
1212
+ * @default 1000
1213
+ */
1214
+ intervalMs?: number;
1215
+ /**
1216
+ * Delay before the first execution in milliseconds
1217
+ * @default 0
1218
+ */
1219
+ delayMs?: number;
1220
+ /**
1221
+ * Number of times to trigger before stopping
1222
+ * @default Infinity
1223
+ */
1224
+ repeatCount?: number;
1225
+ /**
1226
+ * Ensures execution happens at exact intervals (ignoring execution time)
1227
+ * @default false
1228
+ */
1229
+ fixedRate?: boolean;
1230
+ /**
1231
+ * Executes at an exact time of day (ISO HH:mm:ss)
1232
+ * @default null
1233
+ */
1234
+ exactTime?: string;
1235
+ /**
1236
+ * Allows custom date formats for execution times
1237
+ * @default null
1238
+ */
1239
+ timePattern?: string;
1240
+ /**
1241
+ * Adds random delay to prevent synchronized execution spikes
1242
+ * @default 0
1243
+ */
1244
+ jitterMs?: number;
1245
+ }
1246
+ declare class TimerAdapter implements Source<undefined> {
1247
+ private options?;
1248
+ readonly adapterId = "routecraft.adapter.timer";
1249
+ constructor(options?: TimerOptions | undefined);
1250
+ subscribe(_context: CraftContext, handler: (message: undefined, headers?: ExchangeHeaders) => Promise<Exchange>, abortController: AbortController): Promise<void>;
1251
+ }
1252
+
1253
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
1254
+ type QueryParams = Record<string, string | number | boolean>;
1255
+ interface FetchOptions<T = unknown> {
1256
+ method?: HttpMethod;
1257
+ url: string | ((exchange: Exchange<T>) => string);
1258
+ headers?: Record<string, string> | ((exchange: Exchange<T>) => Record<string, string>);
1259
+ query?: QueryParams | ((exchange: Exchange<T>) => QueryParams);
1260
+ body?: unknown | ((exchange: Exchange<T>) => unknown);
1261
+ timeoutMs?: number;
1262
+ throwOnHttpError?: boolean;
1263
+ }
1264
+ type FetchResult<T = string | unknown> = {
1265
+ status: number;
1266
+ headers: Record<string, string>;
1267
+ body: T;
1268
+ url: string;
1269
+ };
1270
+ /**
1271
+ * FetchAdapter can act as a Processor, Enricher, or Destination.
1272
+ * - process: replaces body with FetchResult
1273
+ * - enrich: returns FetchResult for aggregation
1274
+ * - send: performs request as side effect (ignores body)
1275
+ */
1276
+ declare class FetchAdapter<T = unknown, R = FetchResult> implements Enricher<T, R>, Destination<T> {
1277
+ private readonly options;
1278
+ readonly adapterId = "routecraft.adapter.fetch";
1279
+ constructor(options: FetchOptions<T>);
1280
+ enrich(exchange: Exchange<T>): Promise<R>;
1281
+ send(exchange: Exchange<T>): Promise<void>;
1282
+ private performFetch;
1283
+ private resolve;
1284
+ private resolveRequired;
1285
+ private appendQuery;
1286
+ private base;
1287
+ }
1288
+
1289
+ /**
1290
+ * Create a new context builder.
1291
+ *
1292
+ * This is the entry point for creating a new application context.
1293
+ *
1294
+ * @returns A new ContextBuilder instance
1295
+ *
1296
+ * @example
1297
+ * ```typescript
1298
+ * // Create and configure a context
1299
+ * const ctx = context()
1300
+ * .routes(myRoute)
1301
+ * .on('contextStarting', () => console.log('Starting...'))
1302
+ * .build();
1303
+ *
1304
+ * // Start processing
1305
+ * await ctx.start();
1306
+ * ```
1307
+ */
1308
+ declare function context(): ContextBuilder;
1309
+ /**
1310
+ * Create a new route builder.
1311
+ *
1312
+ * This is the entry point for defining routes in a fluent way.
1313
+ *
1314
+ * @returns A new RouteBuilder instance
1315
+ *
1316
+ * @example
1317
+ * ```typescript
1318
+ * // Define a route that processes data
1319
+ * const myRoute = craft()
1320
+ * .from(simple("Hello, World!"))
1321
+ * .transform(data => data.toUpperCase())
1322
+ * .to(log())
1323
+ * ```
1324
+ */
1325
+ declare function craft(): RouteBuilder;
1326
+ /**
1327
+ * Create a simple adapter that produces static or dynamically generated data.
1328
+ *
1329
+ * This adapter can be used as a source in a route to provide data.
1330
+ *
1331
+ * @template T The type of data to produce
1332
+ * @param producer A static value or function that produces a value
1333
+ * @returns A SimpleAdapter instance
1334
+ *
1335
+ * @example
1336
+ * ```typescript
1337
+ * // Static data
1338
+ * craft().from(simple("Hello, World!"))
1339
+ *
1340
+ * // Dynamic data from a function
1341
+ * craft().from(simple(() => new Date().toISOString()))
1342
+ *
1343
+ * // Dynamic data from an async function
1344
+ * craft().from(simple(async () => {
1345
+ * const response = await fetch('https://api.example.com/data');
1346
+ * return response.json();
1347
+ * }))
1348
+ * ```
1349
+ */
1350
+ declare function simple<T = unknown>(producer: (() => T | Promise<T>) | T): SimpleAdapter<T>;
1351
+ /**
1352
+ * Create a no-operation adapter that does nothing.
1353
+ *
1354
+ * This can be useful for testing or as a placeholder.
1355
+ *
1356
+ * @template T The type of data this adapter processes
1357
+ * @returns A NoopAdapter instance
1358
+ *
1359
+ * @example
1360
+ * ```typescript
1361
+ * // Send to a no-op destination during development
1362
+ * craft()
1363
+ * .from(source)
1364
+ * .to(process.env.PROD ? realDestination() : noop())
1365
+ * ```
1366
+ */
1367
+ declare function noop<T = unknown>(): NoopAdapter<T>;
1368
+ /**
1369
+ * Create a logging adapter that logs messages to the console.
1370
+ *
1371
+ * This is useful for debugging and monitoring data flow in routes.
1372
+ *
1373
+ * @template T The type of data this adapter processes
1374
+ * @param formatter Optional function that takes an exchange and returns the value to log.
1375
+ * If not provided, logs exchange ID, body, and headers.
1376
+ * @returns A LogAdapter instance
1377
+ *
1378
+ * @example
1379
+ * ```typescript
1380
+ * // Log data at different points in the route
1381
+ * craft()
1382
+ * .from(source)
1383
+ * .tap(log()) // Log input data
1384
+ * .transform(data => processData(data))
1385
+ * .tap(log()) // Log transformed data
1386
+ * .to(destination)
1387
+ *
1388
+ * // Log with custom formatter
1389
+ * craft()
1390
+ * .from(source)
1391
+ * .tap(log((ex) => `Exchange with id: ${ex.id}`))
1392
+ * .tap(log((ex) => `Body: ${JSON.stringify(ex.body)}`))
1393
+ * .to(destination)
1394
+ * ```
1395
+ */
1396
+ declare function log<T = unknown>(formatter?: (exchange: Exchange<T>) => unknown): LogAdapter<T>;
1397
+ /**
1398
+ * Create a direct adapter for synchronous inter-route communication.
1399
+ *
1400
+ * Direct adapters allow routes to communicate with each other
1401
+ * synchronously with single consumer semantics (Apache Camel style).
1402
+ *
1403
+ * @template T The type of data this adapter processes
1404
+ * @param endpoint The name of the direct endpoint to use
1405
+ * @param options Optional configuration for the direct adapter
1406
+ * @returns A DirectAdapter instance
1407
+ *
1408
+ * @example
1409
+ * ```typescript
1410
+ * // Producer route sends to a direct endpoint
1411
+ * const producerRoute = craft()
1412
+ * .from(source)
1413
+ * .to(direct('my-endpoint'))
1414
+ *
1415
+ * // Consumer route reads from the same endpoint
1416
+ * const consumerRoute = craft()
1417
+ * .from(direct('my-endpoint'))
1418
+ * .to(destination)
1419
+ *
1420
+ * // Register both routes with the context
1421
+ * context().routes([producerRoute, consumerRoute]);
1422
+ * ```
1423
+ */
1424
+ declare function direct<T = unknown>(endpoint: string, options?: Partial<DirectAdapterOptions>): DirectAdapter<T>;
1425
+ /**
1426
+ * Create a timer adapter that produces messages at regular intervals.
1427
+ *
1428
+ * This adapter can be used as a source in a route to trigger processing
1429
+ * on a schedule.
1430
+ *
1431
+ * @param options Configuration for the timer
1432
+ * @returns A TimerAdapter instance
1433
+ *
1434
+ * @example
1435
+ * ```typescript
1436
+ * // Run every 5 seconds
1437
+ * craft()
1438
+ * .from(timer({ intervalMs: 5000 }))
1439
+ * .to(periodicTask)
1440
+ *
1441
+ * // Run 10 times, once per second
1442
+ * craft()
1443
+ * .from(timer({ intervalMs: 1000, repeatCount: 10 }))
1444
+ * .to(batchTask)
1445
+ * ```
1446
+ */
1447
+ declare function timer(options?: TimerOptions): TimerAdapter;
1448
+ /**
1449
+ * Create an HTTP client adapter for making requests.
1450
+ * Acts as processor, enricher, or destination depending on usage site.
1451
+ */
1452
+ declare function fetch<T = unknown, R = unknown>(options: FetchOptions<T>): FetchAdapter<T, R>;
1453
+
1454
+ export { type Adapter, type Aggregator, BatchConsumer, type BatchOptions, type CallableAggregator, type CallableDestination, type CallableEnricher, type CallableFilter, type CallableProcessor, type CallableSource, type CallableSplitter, type CallableTap, type CallableTransformer, type Consumer, type ConsumerType, ContextBuilder, type CraftConfig, CraftContext, DefaultExchange, DefaultRoute, type Destination, DirectAdapter, type DirectAdapterOptions, type DirectChannel, type DirectChannelType, type EnrichAggregator, type Enricher, type Exchange, type ExchangeHeaders, FetchAdapter, type FetchOptions, type FetchResult, type Filter, type HeaderValue, HeadersKeys, LogAdapter, type MergedOptions, type Message, NoopAdapter, OperationType, type Processor, RC, type RCCode, type RCMeta, type Route, RouteBuilder, RouteCraftError, type RouteDefinition, type RouteOptions, SimpleAdapter, SimpleConsumer, type Source, type Splitter, type Step, type StoreRegistry, type Tap, TimerAdapter, type TimerOptions, type Transformer, context, craft, createLogger, defaultEnrichAggregator, direct, error, fetch, log, logger, noop, simple, timer };