@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.
- package/LICENSE +201 -0
- package/README.md +65 -0
- package/dist/index.cjs +9 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1454 -0
- package/dist/index.d.ts +1454 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/index.d.ts
ADDED
|
@@ -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 };
|