@celerity-sdk/core 0.3.0 → 0.4.0

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/dist/index.d.ts CHANGED
@@ -1,49 +1,195 @@
1
- import { Schema, Type, CelerityLayer, InjectionToken, ModuleMetadata, HandlerContext, HandlerResponse, HandlerMetadata, ServiceContainer, Provider, HttpRequest, HttpResponse, FunctionHandlerDefinition, HttpMethod, CelerityLogger } from '@celerity-sdk/types';
2
- export { CelerityLayer, FunctionHandlerDefinition, HandlerContext, HandlerMetadata, HandlerResponse, HttpMethod, HttpRequest, HttpResponse, InjectionToken, ModuleMetadata, Provider, Schema, ServiceContainer, Type } from '@celerity-sdk/types';
3
- import { Request, Response } from '@celerity-sdk/runtime';
1
+ import { Schema, Type, CelerityLayer, InjectionToken, ModuleMetadata, WebSocketEventType, BaseHandlerContext, HandlerType, HandlerMetadata, ServiceContainer, Provider, HttpMethod, HttpRequest, HttpResponse, WebSocketMessage, ConsumerEventInput, EventResult, ScheduleEventInput as ScheduleEventInput$1, MessageAttributes, WebSocketMessageType, CelerityLogger, FunctionHandlerDefinition, GuardDefinition, WebSocketHandlerContext, ConsumerHandlerContext, ScheduleHandlerContext, WebSocketSender, WebSocketSendOptions } from '@celerity-sdk/types';
2
+ export { BaseHandlerContext, BucketEvent, BucketEventType, CelerityLayer, CelerityLogger, ConsumerEventInput, ConsumerHandlerContext, ConsumerMessage, DatastoreEvent, DatastoreEventType, EventResult, FunctionHandlerDefinition, GuardDefinition, GuardHandlerContext, GuardHandlerRequest, HandlerMetadata, HandlerResponse, HandlerType, HttpHandlerContext, HttpMethod, HttpRequest, HttpResponse, InjectionToken, MessageProcessingFailure, ModuleMetadata, NextFunction, Provider, ScheduleEventInput, ScheduleHandlerContext, Schema, ServiceContainer, SourceType, Type, ValidatedConsumerMessage, WebSocketEventType, WebSocketHandlerContext, WebSocketMessage, WebSocketMessageType, WebSocketRequestContext, WebSocketSendOptions, WebSocketSender } from '@celerity-sdk/types';
3
+ import { CoreWebSocketRegistry, JsConsumerEventInput, Request, JsScheduleEventInput, JsEventResult, Response, JsWebSocketMessageInfo } from '@celerity-sdk/runtime';
4
+ export { CoreWebSocketRegistry, JsConsumerEventInput, JsEventResult, JsScheduleEventInput, JsWebSocketMessageInfo } from '@celerity-sdk/runtime';
5
+ export { INJECT_METADATA, USE_RESOURCE_METADATA } from '@celerity-sdk/common';
4
6
 
5
7
  type ControllerMetadata = {
6
8
  prefix?: string;
7
9
  };
10
+ /**
11
+ * Marks a class as a controller — the general-purpose class decorator for
12
+ * handler classes. The class becomes injectable and its decorated methods are
13
+ * registered as handler callbacks. A single controller can mix handler types:
14
+ *
15
+ * - **HTTP handlers** — `@Get()`, `@Post()`, `@Put()`, `@Patch()`, `@Delete()`,
16
+ * `@Head()`, `@Options()` method decorators define HTTP routes.
17
+ * - **Schedule handlers** — `@ScheduleHandler()` is a cross-cutting method
18
+ * decorator that works on any controller type, including `@Controller`.
19
+ * - **Custom / invocable handlers** — `@Invoke("name")` registers a method as
20
+ * a programmatically invocable endpoint.
21
+ *
22
+ * @param prefix - Optional path prefix prepended to all HTTP route paths
23
+ * defined by method decorators within this controller. Uses `{param}` format
24
+ * for path parameters (matching blueprint conventions, not Express `:param`).
25
+ * Has no effect on schedule or invocable handler methods.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * // HTTP controller
30
+ * @Controller("/users")
31
+ * class UserController {
32
+ * @Get("/{id}")
33
+ * async getUser(@Param("id") id: string): Promise<HandlerResponse> { ... }
34
+ * }
35
+ *
36
+ * // Schedule-only controller
37
+ * @Controller()
38
+ * class MaintenanceTasks {
39
+ * @ScheduleHandler("daily-cleanup")
40
+ * async cleanup(): Promise<EventResult> { ... }
41
+ * }
42
+ *
43
+ * // Mixed: HTTP routes + scheduled tasks + invocable methods
44
+ * @Controller("/admin")
45
+ * class AdminController {
46
+ * @Get("/reports")
47
+ * async listReports(): Promise<HandlerResponse> { ... }
48
+ *
49
+ * @ScheduleHandler("weekly-report")
50
+ * async generateWeeklyReport(): Promise<EventResult> { ... }
51
+ *
52
+ * @Invoke("reprocessOrders")
53
+ * async reprocess(@Payload() payload: unknown): Promise<unknown> { ... }
54
+ * }
55
+ * ```
56
+ */
8
57
  declare function Controller(prefix?: string): ClassDecorator;
9
58
 
59
+ /**
60
+ * Registers an HTTP GET handler. The method should return `HandlerResponse`.
61
+ *
62
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
63
+ * Uses `{param}` format for path parameters.
64
+ */
10
65
  declare function Get(path?: string): MethodDecorator;
66
+ /**
67
+ * Registers an HTTP POST handler.
68
+ *
69
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
70
+ */
11
71
  declare function Post(path?: string): MethodDecorator;
72
+ /**
73
+ * Registers an HTTP PUT handler.
74
+ *
75
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
76
+ */
12
77
  declare function Put(path?: string): MethodDecorator;
78
+ /**
79
+ * Registers an HTTP PATCH handler.
80
+ *
81
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
82
+ */
13
83
  declare function Patch(path?: string): MethodDecorator;
84
+ /**
85
+ * Registers an HTTP DELETE handler.
86
+ *
87
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
88
+ */
14
89
  declare function Delete(path?: string): MethodDecorator;
90
+ /**
91
+ * Registers an HTTP HEAD handler.
92
+ *
93
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
94
+ */
15
95
  declare function Head(path?: string): MethodDecorator;
96
+ /**
97
+ * Registers an HTTP OPTIONS handler.
98
+ *
99
+ * @param path - Route path relative to the controller prefix. Defaults to `/`.
100
+ */
16
101
  declare function Options(path?: string): MethodDecorator;
17
102
 
18
- type ParamType = "body" | "query" | "param" | "headers" | "auth" | "request" | "cookies" | "requestId";
103
+ type ParamType = "body" | "query" | "param" | "headers" | "auth" | "token" | "request" | "cookies" | "requestId" | "connectionId" | "messageBody" | "messageId" | "requestContext" | "eventType" | "messages" | "consumerEvent" | "consumerVendor" | "consumerTraceContext" | "scheduleInput" | "scheduleId" | "scheduleExpression" | "scheduleEvent" | "payload" | "invokeContext";
19
104
  type ParamMetadata = {
20
105
  index: number;
21
106
  type: ParamType;
22
107
  key?: string;
23
108
  schema?: Schema;
24
109
  };
110
+ /**
111
+ * Injects the parsed JSON request body into a handler parameter.
112
+ * The raw `textBody` is JSON-parsed automatically; returns `null` if empty.
113
+ *
114
+ * @param schema - Optional Zod-compatible schema (`{ parse(data): T }`) for
115
+ * body validation. When provided, the parsed body is passed through
116
+ * `schema.parse()` before injection.
117
+ */
25
118
  declare function Body(schema?: Schema): ParameterDecorator;
119
+ /**
120
+ * Injects query string parameters into a handler parameter.
121
+ *
122
+ * - `@Query()` — injects the full query object (`Record<string, string | string[]>`)
123
+ * - `@Query("key")` — injects a single query parameter value
124
+ * - `@Query(schema)` — injects the full query object, validated through `schema.parse()`
125
+ * - `@Query("key", schema)` — injects a single value, validated through `schema.parse()`
126
+ */
26
127
  declare function Query(): ParameterDecorator;
27
128
  declare function Query(key: string): ParameterDecorator;
28
129
  declare function Query(schema: Schema): ParameterDecorator;
29
130
  declare function Query(key: string, schema: Schema): ParameterDecorator;
131
+ /**
132
+ * Injects path parameters into a handler parameter. Path params use `{param}`
133
+ * format in route definitions (matching blueprint conventions).
134
+ *
135
+ * - `@Param()` — injects the full path params object (`Record<string, string>`)
136
+ * - `@Param("id")` — injects a single path parameter value
137
+ * - `@Param(schema)` — injects the full params object, validated through `schema.parse()`
138
+ * - `@Param("id", schema)` — injects a single value, validated through `schema.parse()`
139
+ */
30
140
  declare function Param(): ParameterDecorator;
31
141
  declare function Param(key: string): ParameterDecorator;
32
142
  declare function Param(schema: Schema): ParameterDecorator;
33
143
  declare function Param(key: string, schema: Schema): ParameterDecorator;
144
+ /**
145
+ * Injects request headers into a handler parameter.
146
+ *
147
+ * - `@Headers()` — injects the full headers object (`Record<string, string | string[]>`)
148
+ * - `@Headers("content-type")` — injects a single header value
149
+ * - `@Headers(schema)` — injects the full headers object, validated through `schema.parse()`
150
+ * - `@Headers("key", schema)` — injects a single value, validated through `schema.parse()`
151
+ */
34
152
  declare function Headers(): ParameterDecorator;
35
153
  declare function Headers(key: string): ParameterDecorator;
36
154
  declare function Headers(schema: Schema): ParameterDecorator;
37
155
  declare function Headers(key: string, schema: Schema): ParameterDecorator;
156
+ /**
157
+ * Injects the decoded auth payload from the request. This is the identity
158
+ * object populated by guards (e.g. decoded JWT claims), or `null` if the
159
+ * request is unauthenticated.
160
+ */
38
161
  declare function Auth(): ParameterDecorator;
162
+ /**
163
+ * Injects the raw auth token string from the request (e.g. the Bearer token
164
+ * from the Authorization header). This is the unprocessed token before guard
165
+ * validation — use `@Auth()` for the decoded identity payload.
166
+ */
167
+ declare function Token(): ParameterDecorator;
168
+ /**
169
+ * Injects the full `HttpRequest` object into a handler parameter. Use this
170
+ * when you need access to the entire request beyond what individual param
171
+ * decorators provide.
172
+ */
39
173
  declare function Req(): ParameterDecorator;
174
+ /**
175
+ * Injects request cookies into a handler parameter.
176
+ *
177
+ * - `@Cookies()` — injects the full cookies object (`Record<string, string>`)
178
+ * - `@Cookies("session")` — injects a single cookie value
179
+ */
40
180
  declare function Cookies(key?: string): ParameterDecorator;
181
+ /**
182
+ * Injects the unique request ID assigned to this request by the runtime
183
+ * or API Gateway.
184
+ */
41
185
  declare function RequestId(): ParameterDecorator;
42
186
 
43
187
  /**
44
- * Marks a handler class as a custom guard implementation.
45
- * The handler IS the guard in serverless it becomes a Lambda Authorizer,
46
- * in containers the Rust runtime invokes it before protected handlers.
188
+ * Marks a class as a custom guard implementation.
189
+ * The class must have a `check()` method that the runtime invokes before protected handlers.
190
+ *
191
+ * In serverless mode, the guard becomes a Lambda Authorizer.
192
+ * In container mode, the Rust runtime invokes it via `registerGuardHandler`.
47
193
  *
48
194
  * Other handlers reference this guard via `@ProtectedBy("name")`.
49
195
  */
@@ -60,26 +206,476 @@ declare function ProtectedBy(name: string): (target: object, propertyKey?: strin
60
206
  */
61
207
  declare function Public(): MethodDecorator;
62
208
 
209
+ /**
210
+ * Attaches one or more layers to a controller class or individual method.
211
+ * Layers run in declaration order (top-to-bottom) as middleware around the
212
+ * handler, composing into the pipeline: `[system] → [app] → [handler layers]`.
213
+ *
214
+ * Can be applied at class level (all methods) or method level. Class-level
215
+ * layers run before method-level layers. Accepts both layer instances and
216
+ * layer classes (which are resolved from the DI container).
217
+ *
218
+ * @param layers - Layer instances or layer class constructors to attach.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * @Controller("/orders")
223
+ * @UseLayer(LoggingLayer, AuthLayer)
224
+ * class OrderController {
225
+ * @Get("/{id}")
226
+ * @UseLayer(new CacheLayer({ ttl: 60 }))
227
+ * async getOrder(@Param("id") id: string) { ... }
228
+ * }
229
+ * ```
230
+ */
63
231
  declare function UseLayer(...layers: (Type<CelerityLayer> | CelerityLayer)[]): (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
232
+ /**
233
+ * Array-based variant of `@UseLayer()`. Accepts layers as an array instead
234
+ * of rest parameters — useful when layers are composed programmatically.
235
+ */
64
236
  declare function UseLayers(layers: (Type<CelerityLayer> | CelerityLayer)[]): (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
65
237
 
238
+ /**
239
+ * Declares that a handler or controller uses one or more blueprint-defined
240
+ * infrastructure resources. Used by the CLI extraction pipeline to emit
241
+ * `celerity.handler.resource.ref` annotations for handler-to-resource linking.
242
+ *
243
+ * When there is only one resource of a given type in the blueprint, the Go CLI
244
+ * can auto-link via DI inference. `@UseResource` is needed to disambiguate
245
+ * when multiple resources of the same type exist.
246
+ *
247
+ * Can be applied at class level (default for all methods) or method level
248
+ * (additional resources for that handler). Multiple decorators accumulate.
249
+ *
250
+ * @param resourceNames - One or more blueprint resource names.
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * @Controller("/orders")
255
+ * @UseResource("ordersBucket")
256
+ * class OrderController {
257
+ * @Get("/{id}")
258
+ * @UseResource("ordersCache")
259
+ * async getOrder(@Param("id") id: string) { ... }
260
+ *
261
+ * @Post("/")
262
+ * async createOrder(@Body() body: CreateOrderDto) { ... }
263
+ * }
264
+ * ```
265
+ */
266
+ declare function UseResource(...resourceNames: string[]): (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
267
+ /**
268
+ * Array-based variant of `@UseResource()`. Accepts resource names as an array
269
+ * instead of rest parameters — useful when resource names are composed
270
+ * programmatically.
271
+ */
272
+ declare function UseResources(resourceNames: string[]): (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
273
+
274
+ /**
275
+ * Attaches custom key-value metadata to a controller class or method.
276
+ * Metadata is accessible to guards and layers via
277
+ * `context.metadata.get(key)` at runtime.
278
+ *
279
+ * Multiple `@SetMetadata` decorators accumulate on the same target.
280
+ * Method-level metadata is merged with (and overrides) class-level metadata.
281
+ *
282
+ * @param key - Metadata key.
283
+ * @param value - Metadata value (any serializable type).
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * @Controller("/admin")
288
+ * @SetMetadata("roles", ["admin"])
289
+ * class AdminController {
290
+ * @Get("/")
291
+ * @SetMetadata("action", "admin:list")
292
+ * async list() { ... }
293
+ * }
294
+ * ```
295
+ */
66
296
  declare function SetMetadata(key: string, value: unknown): (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
297
+ /**
298
+ * Shorthand for `@SetMetadata("action", value)`. Sets the `action` metadata
299
+ * key, commonly used by guards to determine authorization rules.
300
+ */
67
301
  declare function Action(value: unknown): (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
68
302
 
303
+ /**
304
+ * Marks a class as injectable into the DI container. Required for any class
305
+ * that should be resolved as a dependency — services, repositories, etc.
306
+ *
307
+ * Controller and handler decorators (`@Controller`, `@WebSocketController`,
308
+ * `@Consumer`, `@Guard`) set this automatically, so `@Injectable()` is only
309
+ * needed for non-handler service classes.
310
+ *
311
+ * @example
312
+ * ```ts
313
+ * @Injectable()
314
+ * class OrderService {
315
+ * constructor(private db: DatabaseClient) {}
316
+ * }
317
+ * ```
318
+ */
69
319
  declare function Injectable(): ClassDecorator;
320
+ /**
321
+ * Overrides the DI token for a constructor parameter. By default the container
322
+ * resolves dependencies using the class type from `emitDecoratorMetadata`. Use
323
+ * `@Inject()` when you need to inject by a symbol, string token, or abstract
324
+ * class that differs from the declared parameter type.
325
+ *
326
+ * @param token - The DI token (class, symbol, or string) to resolve.
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * @Injectable()
331
+ * class OrderService {
332
+ * constructor(@Inject(DB_TOKEN) private db: DatabaseClient) {}
333
+ * }
334
+ * ```
335
+ */
70
336
  declare function Inject(token: InjectionToken): ParameterDecorator;
71
337
 
338
+ /**
339
+ * Declares a module — the organizational unit for grouping controllers,
340
+ * providers, function handlers, and sub-modules. The root module is the
341
+ * entry point for bootstrapping the application.
342
+ *
343
+ * @param metadata - Module configuration including:
344
+ * - `imports` — sub-modules to compose into this module's scope
345
+ * - `controllers` — handler classes (`@Controller`, `@WebSocketController`, `@Consumer`, etc.)
346
+ * - `providers` — DI providers (classes, factories, or values)
347
+ * - `functionHandlers` — function-based handler definitions
348
+ * - `guards` — guard classes or definitions
349
+ * - `layers` — application-level layers applied to all handlers in this module
350
+ *
351
+ * @example
352
+ * ```ts
353
+ * @Module({
354
+ * imports: [DatabaseModule],
355
+ * controllers: [UserController, OrderConsumer],
356
+ * providers: [UserService, OrderService],
357
+ * })
358
+ * class AppModule {}
359
+ * ```
360
+ */
72
361
  declare function Module(metadata: ModuleMetadata): ClassDecorator;
73
362
 
363
+ type WebSocketEventMetadata = {
364
+ eventType: WebSocketEventType;
365
+ route: string;
366
+ };
367
+ /**
368
+ * Marks a class as a WebSocket controller. The class becomes injectable and
369
+ * its `@OnConnect()`, `@OnMessage()`, and `@OnDisconnect()` methods are
370
+ * registered as WebSocket handler callbacks.
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * @WebSocketController()
375
+ * class ChatHandler {
376
+ * @OnMessage("chat")
377
+ * async onChat(@ConnectionId() id: string, @MessageBody() body: unknown): Promise<void> { ... }
378
+ * }
379
+ * ```
380
+ */
381
+ declare function WebSocketController(): ClassDecorator;
382
+ /**
383
+ * Handles WebSocket connection events. Invoked when a client establishes a
384
+ * new WebSocket connection. Registered with the fixed route `$connect`.
385
+ */
386
+ declare function OnConnect(): MethodDecorator;
387
+ /**
388
+ * Handles WebSocket message events. Invoked when a connected client sends
389
+ * a message.
390
+ *
391
+ * @param route - Optional route key for message dispatching. Defaults to
392
+ * `$default` which catches all messages not matched by a specific route.
393
+ * Custom routes enable action-based routing (e.g. `"chat"`, `"ping"`).
394
+ */
395
+ declare function OnMessage(route?: string): MethodDecorator;
396
+ /**
397
+ * Handles WebSocket disconnection events. Invoked when a client disconnects.
398
+ * Registered with the fixed route `$disconnect`.
399
+ */
400
+ declare function OnDisconnect(): MethodDecorator;
401
+
402
+ /**
403
+ * Injects the WebSocket connection ID into a handler parameter.
404
+ * This is the unique identifier for the client's connection, used to send
405
+ * messages back via `WebSocketSender.sendMessage(connectionId, data)`.
406
+ */
407
+ declare function ConnectionId(): ParameterDecorator;
408
+ /**
409
+ * Injects the parsed message body from a WebSocket message event.
410
+ * Returns the `jsonBody` field from the `WebSocketMessage`.
411
+ *
412
+ * @param schema - Optional Zod-compatible schema (`{ parse(data): T }`) for
413
+ * body validation. When provided, the body is passed through
414
+ * `schema.parse()` before injection.
415
+ */
416
+ declare function MessageBody(schema?: Schema): ParameterDecorator;
417
+ /**
418
+ * Injects the unique message ID from a WebSocket message event.
419
+ */
420
+ declare function MessageId(): ParameterDecorator;
421
+ /**
422
+ * Injects the `WebSocketRequestContext` from the connection handshake.
423
+ * Contains request metadata from the initial HTTP upgrade: request ID,
424
+ * path, headers, query params, cookies, client IP, and auth payload.
425
+ */
426
+ declare function RequestContext(): ParameterDecorator;
427
+ /**
428
+ * Injects the WebSocket event type: `"connect"`, `"message"`, or
429
+ * `"disconnect"`. Useful when a single method handles multiple event types.
430
+ */
431
+ declare function EventType(): ParameterDecorator;
432
+
433
+ type ConsumerMetadata = {
434
+ sourceId?: string;
435
+ };
436
+ type ConsumerHandlerMetadata = {
437
+ route?: string;
438
+ };
439
+ /**
440
+ * Marks a class as a consumer controller that processes batches of messages
441
+ * from an event source (SQS, Kafka, Pub/Sub, etc.).
442
+ *
443
+ * The class becomes injectable and its `@MessageHandler()` methods are
444
+ * registered as consumer handler callbacks.
445
+ *
446
+ * @param sourceId - Optional annotation hint that tells the deploy engine
447
+ * which blueprint-defined consumer source this handler should be wired to.
448
+ * Does not create infrastructure — the blueprint defines the actual source.
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * @Consumer("orders-queue")
453
+ * class OrderConsumer {
454
+ * @MessageHandler()
455
+ * async process(@Messages(OrderSchema) messages: ValidatedConsumerMessage<Order>[]): Promise<EventResult> {
456
+ * // ...
457
+ * }
458
+ * }
459
+ * ```
460
+ */
461
+ declare function Consumer(sourceId?: string): ClassDecorator;
462
+ /**
463
+ * Marks a method inside a `@Consumer()` class as a message handler.
464
+ *
465
+ * The method should return `Promise<EventResult>` with partial failure
466
+ * semantics — individual message failures are reported via `failures[]`
467
+ * without failing the entire batch.
468
+ *
469
+ * @param route - Optional routing key for message dispatching. The CLI
470
+ * extracts this as `celerity.handler.consumer.route` and the deploy engine
471
+ * merges it into the consumer source's routing configuration. The blueprint
472
+ * can override. When omitted, the method name is used as the handler tag.
473
+ */
474
+ declare function MessageHandler(route?: string): MethodDecorator;
475
+
476
+ /**
477
+ * Injects the message batch into a `@MessageHandler()` method parameter.
478
+ *
479
+ * - **Without a schema:** injects `ConsumerMessage[]` with raw `body: string`
480
+ * fields. The handler is responsible for parsing each message body.
481
+ * - **With a schema:** the pipeline JSON-parses each `msg.body` and runs
482
+ * `schema.parse()`. Messages that pass validation are injected as
483
+ * `ValidatedConsumerMessage<T>[]` with a typed `parsedBody` field. Messages
484
+ * that fail JSON parsing or schema validation are excluded from the batch
485
+ * and automatically reported as `MessageProcessingFailure` entries, merged
486
+ * into the handler's returned `EventResult`.
487
+ *
488
+ * @param schema - Optional Zod-compatible schema (`{ parse(data): T }`) for
489
+ * per-message body validation.
490
+ */
491
+ declare function Messages(schema?: Schema): ParameterDecorator;
492
+ /**
493
+ * Injects the full `ConsumerEventInput` envelope into a `@MessageHandler()`
494
+ * method parameter. This includes the raw message batch, handler tag, vendor
495
+ * metadata, and trace context.
496
+ *
497
+ * Use this when you need access to the entire event beyond just the messages —
498
+ * for example, to inspect `vendor` metadata or `traceContext`. Analogous to
499
+ * `@Req()` for HTTP handlers.
500
+ */
501
+ declare function EventInput(): ParameterDecorator;
502
+ /**
503
+ * Injects the vendor-specific metadata from the consumer event. This is the
504
+ * platform-specific envelope data (e.g. SQS event source ARN, Kafka topic
505
+ * metadata) — not the per-message vendor attributes.
506
+ *
507
+ * Equivalent to `event.vendor` from `@EventInput()`.
508
+ */
509
+ declare function Vendor(): ParameterDecorator;
510
+ /**
511
+ * Injects the trace context from the consumer event, if present.
512
+ *
513
+ * Returns `Record<string, string>` containing W3C Trace Context headers
514
+ * (e.g. `traceparent`) and platform-specific trace IDs, or `null` if no
515
+ * trace context was propagated.
516
+ */
517
+ declare function ConsumerTraceContext(): ParameterDecorator;
518
+
519
+ type ScheduleHandlerMetadata = {
520
+ scheduleId?: string;
521
+ schedule?: string;
522
+ };
523
+ type ScheduleHandlerOptions = {
524
+ scheduleId?: string;
525
+ schedule?: string;
526
+ };
527
+ /**
528
+ * Marks a method as a schedule handler — a task triggered by a time-based
529
+ * schedule (EventBridge rule, Cloud Scheduler, etc.).
530
+ *
531
+ * This is a **cross-cutting** method decorator that works on any controller
532
+ * type (`@Controller`, `@WebSocketController`, `@Consumer`). There is no
533
+ * `@ScheduleController` class decorator — schedule-only classes use
534
+ * `@Controller()`.
535
+ *
536
+ * The method should return `Promise<EventResult>` to report success/failure.
537
+ *
538
+ * @param arg - Optional string or options object. String parsing:
539
+ * - No args → fully blueprint-driven (no annotations)
540
+ * - String with `rate(` or `cron(` prefix → `schedule` expression annotation
541
+ * - String without prefix → `scheduleId` annotation hint for deploy engine
542
+ * - Object → explicit `{ scheduleId?, schedule? }`
543
+ *
544
+ * @example
545
+ * ```ts
546
+ * @Controller()
547
+ * class MaintenanceTasks {
548
+ * @ScheduleHandler("daily-cleanup")
549
+ * async cleanup(@ScheduleInput() input: unknown): Promise<EventResult> {
550
+ * // scheduleId hint — blueprint defines the actual schedule
551
+ * }
552
+ *
553
+ * @ScheduleHandler("rate(1 day)")
554
+ * async sync(): Promise<EventResult> {
555
+ * // schedule expression annotation — blueprint can override
556
+ * }
557
+ *
558
+ * @ScheduleHandler({ scheduleId: "weekly-report", schedule: "cron(0 9 ? * MON *)" })
559
+ * async report(): Promise<EventResult> {
560
+ * // explicit object with both fields
561
+ * }
562
+ * }
563
+ * ```
564
+ */
565
+ declare function ScheduleHandler(): MethodDecorator;
566
+ declare function ScheduleHandler(scheduleIdOrExpression: string): MethodDecorator;
567
+ declare function ScheduleHandler(options: ScheduleHandlerOptions): MethodDecorator;
568
+
569
+ /**
570
+ * Injects the schedule event's `input` payload into a `@ScheduleHandler()`
571
+ * method parameter.
572
+ *
573
+ * - **Without a schema:** injects the raw `event.input` as `unknown`.
574
+ * - **With a schema:** the pipeline validates `event.input` through
575
+ * `schema.parse()` before the handler runs. If validation fails, the
576
+ * handler is not invoked and the pipeline returns
577
+ * `{ success: false, errorMessage }`.
578
+ *
579
+ * @param schema - Optional Zod-compatible schema (`{ parse(data): T }`) for
580
+ * input validation.
581
+ */
582
+ declare function ScheduleInput(schema?: Schema): ParameterDecorator;
583
+ /**
584
+ * Injects the schedule ID from the event into a `@ScheduleHandler()`
585
+ * method parameter. This is the identifier of the schedule rule that
586
+ * triggered the handler (e.g. `"daily-cleanup"`).
587
+ */
588
+ declare function ScheduleId(): ParameterDecorator;
589
+ /**
590
+ * Injects the schedule expression from the event into a `@ScheduleHandler()`
591
+ * method parameter. This is the actual schedule expression that triggered
592
+ * the handler (e.g. `"rate(1 day)"` or `"cron(0 9 * * *)"`).
593
+ */
594
+ declare function ScheduleExpression(): ParameterDecorator;
595
+ /**
596
+ * Injects the full `ScheduleEventInput` envelope into a `@ScheduleHandler()`
597
+ * method parameter. This includes the schedule ID, expression, message ID,
598
+ * input payload, vendor metadata, and trace context.
599
+ *
600
+ * Use this when you need access to the entire event beyond just the input —
601
+ * analogous to `@Req()` for HTTP handlers or `@EventInput()` for consumers.
602
+ */
603
+ declare function ScheduleEventInput(): ParameterDecorator;
604
+
605
+ type InvokeMetadata = {
606
+ name: string;
607
+ };
608
+ /**
609
+ * Marks a method as a custom/invocable handler — a programmatic invocation
610
+ * endpoint identified by name, callable via `app.invokeHandler(name, payload)`
611
+ * or the runtime's `/runtime/handlers/invoke` endpoint.
612
+ *
613
+ * This is a **cross-cutting** method decorator that works on any controller
614
+ * type (`@Controller`, `@WebSocketController`, `@Consumer`). A single class
615
+ * can mix HTTP routes, scheduled tasks, and invocable methods.
616
+ *
617
+ * @param name - The handler name used for invocation lookup. Must be unique
618
+ * across all registered custom handlers.
619
+ *
620
+ * @example
621
+ * ```ts
622
+ * // Standalone invocable handler
623
+ * @Controller()
624
+ * class PaymentHandlers {
625
+ * @Invoke("processPayment")
626
+ * async process(@Payload(PaymentSchema) payload: PaymentInput): Promise<PaymentResult> {
627
+ * return this.paymentService.process(payload);
628
+ * }
629
+ * }
630
+ *
631
+ * // Mixed: HTTP routes + invocable methods
632
+ * @Controller("/payments")
633
+ * class PaymentController {
634
+ * @Get("/{id}")
635
+ * async getPayment(@Param("id") id: string): Promise<HandlerResponse> { ... }
636
+ *
637
+ * @Invoke("processPayment")
638
+ * async processPayment(@Payload(PaymentSchema) payload: PaymentInput): Promise<PaymentResult> {
639
+ * return this.paymentService.process(payload);
640
+ * }
641
+ * }
642
+ * ```
643
+ */
644
+ declare function Invoke(name: string): MethodDecorator;
645
+
646
+ /**
647
+ * Injects the invocation payload into an `@Invoke()` method parameter.
648
+ *
649
+ * - **Without a schema:** injects the raw payload as `unknown`. The handler
650
+ * is responsible for any validation.
651
+ * - **With a schema:** the pipeline validates the payload through
652
+ * `schema.parse()` before the handler runs. If validation fails, the
653
+ * error is re-thrown to the caller.
654
+ *
655
+ * @param schema - Optional Zod-compatible schema (`{ parse(data): T }`) for
656
+ * payload validation.
657
+ */
658
+ declare function Payload(schema?: Schema): ParameterDecorator;
659
+ /**
660
+ * Injects the `BaseHandlerContext` into an `@Invoke()` method parameter.
661
+ * Provides access to the handler metadata store, DI container, and
662
+ * optional request-scoped logger.
663
+ */
664
+ declare function InvokeContext(): ParameterDecorator;
665
+
74
666
  type ValidationSchemas = {
75
667
  body?: Schema;
76
668
  params?: Schema;
77
669
  query?: Schema;
78
670
  headers?: Schema;
671
+ wsMessageBody?: Schema;
672
+ consumerMessage?: Schema;
673
+ scheduleInput?: Schema;
674
+ customPayload?: Schema;
79
675
  };
80
- declare function validate(schemas: ValidationSchemas): CelerityLayer;
676
+ declare function validate(schemas: ValidationSchemas): CelerityLayer<BaseHandlerContext>;
81
677
 
82
- declare function runLayerPipeline(layers: (CelerityLayer | Type<CelerityLayer>)[], context: HandlerContext, handler: () => Promise<HandlerResponse>): Promise<HandlerResponse>;
678
+ declare function runLayerPipeline<TContext extends BaseHandlerContext>(layers: (CelerityLayer<TContext> | Type<CelerityLayer<TContext>>)[], context: TContext, handler: () => Promise<unknown>, handlerType?: HandlerType): Promise<unknown>;
83
679
 
84
680
  declare function createDefaultSystemLayers(): Promise<CelerityLayer[]>;
85
681
 
@@ -152,61 +748,78 @@ declare function getProviderDependencyTokens(provider: Provider<any>): Injection
152
748
  declare const APP_CONFIG: unique symbol;
153
749
  declare const RUNTIME_APP: unique symbol;
154
750
 
155
- type ResolvedHandler = {
751
+ type ResolvedHandlerBase = {
156
752
  id?: string;
157
- path?: string;
158
- method?: string;
159
- protectedBy: string[];
160
- layers: (CelerityLayer | Type<CelerityLayer>)[];
161
- isPublic: boolean;
162
- paramMetadata: ParamMetadata[];
163
- customMetadata: Record<string, unknown>;
164
753
  handlerFn: (...args: unknown[]) => unknown;
165
754
  handlerInstance?: object;
166
755
  isFunctionHandler?: boolean;
167
756
  injectTokens?: InjectionToken[];
757
+ layers: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
758
+ paramMetadata: ParamMetadata[];
759
+ customMetadata: Record<string, unknown>;
168
760
  };
169
- type PipelineOptions = {
170
- container: ServiceContainer;
171
- systemLayers?: (CelerityLayer | Type<CelerityLayer>)[];
172
- appLayers?: (CelerityLayer | Type<CelerityLayer>)[];
761
+ type GuardableFields = {
762
+ protectedBy: string[];
763
+ isPublic: boolean;
173
764
  };
174
- declare function executeHandlerPipeline(handler: ResolvedHandler, request: HttpRequest, options: PipelineOptions): Promise<HttpResponse>;
175
-
176
- type ModuleNode = {
177
- moduleClass: Type;
178
- ownTokens: Set<InjectionToken>;
179
- exports: Set<InjectionToken>;
180
- imports: Type[];
181
- controllers: Type[];
182
- functionHandlers: FunctionHandlerDefinition[];
183
- providers: (Type | (Provider & {
184
- provide: InjectionToken;
185
- }))[];
765
+ type ResolvedHttpHandler = ResolvedHandlerBase & GuardableFields & {
766
+ type: "http";
767
+ path?: string;
768
+ method?: HttpMethod;
769
+ };
770
+ type ResolvedWebSocketHandler = ResolvedHandlerBase & GuardableFields & {
771
+ type: "websocket";
772
+ route: string;
773
+ };
774
+ type ResolvedConsumerHandler = ResolvedHandlerBase & {
775
+ type: "consumer";
776
+ handlerTag: string;
777
+ };
778
+ type ResolvedScheduleHandler = ResolvedHandlerBase & {
779
+ type: "schedule";
780
+ handlerTag: string;
781
+ };
782
+ type ResolvedCustomHandler = ResolvedHandlerBase & {
783
+ type: "custom";
784
+ name: string;
785
+ };
786
+ type ResolvedHandler = ResolvedHttpHandler | ResolvedWebSocketHandler | ResolvedConsumerHandler | ResolvedScheduleHandler | ResolvedCustomHandler;
787
+ type ResolvedGuard = {
788
+ name: string;
789
+ handlerFn: (...args: unknown[]) => unknown;
790
+ handlerInstance?: object;
791
+ paramMetadata: ParamMetadata[];
792
+ customMetadata: Record<string, unknown>;
793
+ injectTokens?: InjectionToken[];
794
+ isFunctionGuard?: boolean;
186
795
  };
187
- type ModuleGraph = Map<Type, ModuleNode>;
188
- /**
189
- * Builds a module graph by walking the module tree depth-first, collecting
190
- * all metadata into a graph structure without any side effects.
191
- *
192
- * Detects circular module imports and deduplicates visited modules.
193
- */
194
- declare function buildModuleGraph(rootModule: Type): ModuleGraph;
195
- /**
196
- * Registers all providers and controllers from the module graph into the
197
- * DI container.
198
- */
199
- declare function registerModuleGraph(graph: ModuleGraph, container: Container): void;
200
796
 
201
797
  declare class HandlerRegistry {
202
- private handlers;
203
- getHandler(path: string, method: string): ResolvedHandler | undefined;
204
- getHandlerById(id: string): ResolvedHandler | undefined;
798
+ private byType;
799
+ private exactLookup;
800
+ private byId;
801
+ private guards;
802
+ register(handler: ResolvedHandler): void;
803
+ getHandler(type: "http", routingKey: string): ResolvedHttpHandler | undefined;
804
+ getHandler(type: "websocket", routingKey: string): ResolvedWebSocketHandler | undefined;
805
+ getHandler(type: "consumer", routingKey: string): ResolvedConsumerHandler | undefined;
806
+ getHandler(type: "schedule", routingKey: string): ResolvedScheduleHandler | undefined;
807
+ getHandler(type: "custom", routingKey: string): ResolvedCustomHandler | undefined;
808
+ getHandlerById<T extends HandlerType>(type: T, id: string): Extract<ResolvedHandler, {
809
+ type: T;
810
+ }> | undefined;
811
+ getHandlersByType<T extends HandlerType>(type: T): Extract<ResolvedHandler, {
812
+ type: T;
813
+ }>[];
205
814
  getAllHandlers(): ResolvedHandler[];
206
- populateFromGraph(graph: ModuleGraph, container: Container): Promise<void>;
207
- scanModule(moduleClass: Type, container: Container): Promise<void>;
208
- private registerClassHandler;
209
- private registerFunctionHandler;
815
+ registerGuard(guard: ResolvedGuard): void;
816
+ getGuard(name: string): ResolvedGuard | undefined;
817
+ getAllGuards(): ResolvedGuard[];
818
+ /**
819
+ * HTTP routing uses path-pattern matching: `"GET /items/{id}"` matches `"GET /items/42"`.
820
+ * The routing key format is `"METHOD path"` (e.g., `"GET /items/{id}"`).
821
+ */
822
+ private findHttpHandler;
210
823
  }
211
824
 
212
825
  declare class CelerityApplication {
@@ -224,9 +837,21 @@ declare class CelerityApplication {
224
837
  getAppLayers(): (CelerityLayer | Type<CelerityLayer>)[];
225
838
  }
226
839
 
840
+ type PipelineOptions = {
841
+ container: ServiceContainer;
842
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
843
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
844
+ handlerName?: string;
845
+ };
846
+ declare function executeHttpPipeline(handler: ResolvedHandlerBase, request: HttpRequest, options: PipelineOptions): Promise<HttpResponse>;
847
+
227
848
  type ServerlessHandler = (event: unknown, context: unknown) => Promise<unknown>;
228
849
  interface ServerlessAdapter {
229
- createHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
850
+ createHttpHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
851
+ createWebSocketHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
852
+ createConsumerHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
853
+ createScheduleHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
854
+ createCustomHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
230
855
  }
231
856
 
232
857
  declare class ServerlessApplication {
@@ -237,7 +862,8 @@ declare class ServerlessApplication {
237
862
  private appLayers;
238
863
  private handler;
239
864
  constructor(registry: HandlerRegistry, container: Container, adapter: ServerlessAdapter, systemLayers?: (CelerityLayer | Type<CelerityLayer>)[], appLayers?: (CelerityLayer | Type<CelerityLayer>)[]);
240
- start(): Promise<ServerlessHandler>;
865
+ createHandler(type: HandlerType): ServerlessHandler;
866
+ start(type?: HandlerType): Promise<ServerlessHandler>;
241
867
  close(): Promise<void>;
242
868
  getHandler(): ServerlessHandler;
243
869
  getContainer(): Container;
@@ -250,7 +876,11 @@ declare class TestingApplication {
250
876
  private systemLayers;
251
877
  private appLayers;
252
878
  constructor(registry: HandlerRegistry, container: Container, systemLayers?: (CelerityLayer | Type<CelerityLayer>)[], appLayers?: (CelerityLayer | Type<CelerityLayer>)[]);
253
- inject(request: HttpRequest): Promise<HttpResponse>;
879
+ injectHttp(request: HttpRequest): Promise<HttpResponse>;
880
+ injectWebSocket(route: string, message: WebSocketMessage): Promise<void>;
881
+ injectConsumer(handlerTag: string, event: ConsumerEventInput): Promise<EventResult>;
882
+ injectSchedule(handlerTag: string, event: ScheduleEventInput$1): Promise<EventResult>;
883
+ injectCustom(name: string, payload?: unknown): Promise<unknown>;
254
884
  getContainer(): Container;
255
885
  getRegistry(): HandlerRegistry;
256
886
  }
@@ -265,6 +895,39 @@ type MockRequestOptions = {
265
895
  clientIp?: string;
266
896
  };
267
897
  declare function mockRequest(method: HttpMethod, path: string, options?: MockRequestOptions): HttpRequest;
898
+ type MockWebSocketMessageOptions = {
899
+ messageType?: WebSocketMessageType;
900
+ eventType?: WebSocketEventType;
901
+ connectionId?: string;
902
+ messageId?: string;
903
+ jsonBody?: unknown;
904
+ binaryBody?: Buffer;
905
+ traceContext?: Record<string, string> | null;
906
+ };
907
+ declare function mockWebSocketMessage(options?: MockWebSocketMessageOptions): WebSocketMessage;
908
+ type MockConsumerMessage = {
909
+ messageId?: string;
910
+ body: string;
911
+ source?: string;
912
+ sourceType?: string;
913
+ sourceName?: string;
914
+ eventType?: string;
915
+ messageAttributes?: MessageAttributes;
916
+ };
917
+ type MockConsumerEventOptions = {
918
+ vendor?: unknown;
919
+ traceContext?: Record<string, string> | null;
920
+ };
921
+ declare function mockConsumerEvent(handlerTag: string, messages: MockConsumerMessage[], options?: MockConsumerEventOptions): ConsumerEventInput;
922
+ type MockScheduleEventOptions = {
923
+ scheduleId?: string;
924
+ messageId?: string;
925
+ schedule?: string;
926
+ input?: unknown;
927
+ vendor?: unknown;
928
+ traceContext?: Record<string, string> | null;
929
+ };
930
+ declare function mockScheduleEvent(handlerTag: string, options?: MockScheduleEventOptions): ScheduleEventInput$1;
268
931
 
269
932
  type CreateOptions = {
270
933
  adapter?: ServerlessAdapter;
@@ -294,7 +957,7 @@ type HttpHandlerRequest<TBody = unknown> = {
294
957
  userAgent: string | null;
295
958
  contentType: string | null;
296
959
  };
297
- type HttpHandlerContext = {
960
+ type HttpFunctionContext = {
298
961
  requestId: string;
299
962
  requestTime: string;
300
963
  metadata: HandlerMetadata;
@@ -318,7 +981,7 @@ type HttpHandlerConfig<TBody = unknown> = {
318
981
  metadata?: Record<string, unknown>;
319
982
  };
320
983
  type HttpHandlerOptions<TBody = unknown> = Omit<HttpHandlerConfig<TBody>, "path" | "method">;
321
- type HttpHandlerFn<TBody = unknown> = (req: HttpHandlerRequest<TBody>, ctx: HttpHandlerContext, ...deps: unknown[]) => unknown;
984
+ type HttpHandlerFn<TBody = unknown> = (req: HttpHandlerRequest<TBody>, ctx: HttpFunctionContext, ...deps: unknown[]) => unknown;
322
985
  declare function createHttpHandler<TBody = unknown>(config: HttpHandlerConfig<TBody>, handler: HttpHandlerFn<TBody>): FunctionHandlerDefinition;
323
986
  declare function httpGet(path: string, handler: HttpHandlerFn): FunctionHandlerDefinition;
324
987
  declare function httpGet(path: string, options: HttpHandlerOptions, handler: HttpHandlerFn): FunctionHandlerDefinition;
@@ -331,6 +994,145 @@ declare function httpPatch<TBody = unknown>(path: string, options: HttpHandlerOp
331
994
  declare function httpDelete(path: string, handler: HttpHandlerFn): FunctionHandlerDefinition;
332
995
  declare function httpDelete(path: string, options: HttpHandlerOptions, handler: HttpHandlerFn): FunctionHandlerDefinition;
333
996
 
997
+ type GuardConfig = {
998
+ name?: string;
999
+ inject?: InjectionToken[];
1000
+ metadata?: Record<string, unknown>;
1001
+ };
1002
+ /**
1003
+ * The request context provided to a guard handler.
1004
+ * Mirrors the Rust runtime's `AuthGuardValidateInput` + `RequestInfo`.
1005
+ */
1006
+ type GuardRequest = {
1007
+ token: string;
1008
+ headers: Record<string, string | string[]>;
1009
+ query: Record<string, string | string[]>;
1010
+ cookies: Record<string, string>;
1011
+ body: unknown;
1012
+ requestId: string;
1013
+ clientIp: string;
1014
+ };
1015
+ type GuardContext = {
1016
+ metadata: HandlerMetadata;
1017
+ container: ServiceContainer;
1018
+ logger?: CelerityLogger;
1019
+ /**
1020
+ * Claims accumulated from preceding guards in the chain.
1021
+ * Keyed by guard name (e.g. `{ jwt: { sub: "user-1", ... } }`).
1022
+ * Empty object for the first guard in the chain.
1023
+ */
1024
+ auth: Record<string, unknown>;
1025
+ };
1026
+ /**
1027
+ * Guard handler function signature.
1028
+ * Return the claims object to attach to `request.auth.<guardName>`,
1029
+ * or throw `ForbiddenException`/`UnauthorizedException` to reject.
1030
+ */
1031
+ type GuardHandlerFn = (req: GuardRequest, ctx: GuardContext, ...deps: unknown[]) => unknown;
1032
+ declare function createGuard(config: GuardConfig, handler: GuardHandlerFn): GuardDefinition;
1033
+
1034
+ type WebSocketHandlerConfig = {
1035
+ route?: string;
1036
+ protectedBy?: string[];
1037
+ schema?: Schema;
1038
+ inject?: InjectionToken[];
1039
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1040
+ metadata?: Record<string, unknown>;
1041
+ };
1042
+ type WebSocketHandlerFn = (message: WebSocketMessage, ctx: WebSocketHandlerContext, ...deps: unknown[]) => Promise<void> | void;
1043
+ declare function createWebSocketHandler(config: WebSocketHandlerConfig, handler: WebSocketHandlerFn): FunctionHandlerDefinition;
1044
+
1045
+ type ConsumerHandlerConfig = {
1046
+ route?: string;
1047
+ messageSchema?: Schema;
1048
+ inject?: InjectionToken[];
1049
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1050
+ metadata?: Record<string, unknown>;
1051
+ };
1052
+ type ConsumerHandlerFn = (event: ConsumerEventInput, ctx: ConsumerHandlerContext, ...deps: unknown[]) => Promise<EventResult>;
1053
+ declare function createConsumerHandler(config: ConsumerHandlerConfig, handler: ConsumerHandlerFn): FunctionHandlerDefinition;
1054
+
1055
+ type ScheduleHandlerConfig<T = unknown> = {
1056
+ scheduleId?: string;
1057
+ schedule?: string;
1058
+ schema?: Schema<T>;
1059
+ inject?: InjectionToken[];
1060
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1061
+ metadata?: Record<string, unknown>;
1062
+ };
1063
+ type ScheduleHandlerFn = (event: ScheduleEventInput$1, ctx: ScheduleHandlerContext, ...deps: unknown[]) => Promise<EventResult>;
1064
+ /**
1065
+ * Creates a function-based schedule handler definition.
1066
+ *
1067
+ * Function handlers are blueprint-first — the schedule expression, timezone,
1068
+ * and handler binding are all defined in the blueprint. The handler declares
1069
+ * its dependencies and provides the task logic.
1070
+ *
1071
+ * @example
1072
+ * ```ts
1073
+ * // Minimal — blueprint defines everything
1074
+ * const dailyCleanup = createScheduleHandler(
1075
+ * { inject: [CleanupService] },
1076
+ * async (event, ctx, cleanupService: CleanupService) => {
1077
+ * await cleanupService.run();
1078
+ * return { success: true };
1079
+ * },
1080
+ * );
1081
+ *
1082
+ * // With scheduleId hint for deploy engine auto-wiring
1083
+ * const weeklyReport = createScheduleHandler("weekly-report", {
1084
+ * inject: [ReportService],
1085
+ * }, async (event, ctx, reportService: ReportService) => {
1086
+ * await reportService.generate();
1087
+ * return { success: true };
1088
+ * });
1089
+ *
1090
+ * // With expression for prototyping / single-environment apps
1091
+ * const hourlySync = createScheduleHandler("rate(1 hour)", {
1092
+ * inject: [SyncService],
1093
+ * }, async (event, ctx, syncService: SyncService) => {
1094
+ * await syncService.run();
1095
+ * return { success: true };
1096
+ * });
1097
+ * ```
1098
+ */
1099
+ declare function createScheduleHandler(config: ScheduleHandlerConfig, handler: ScheduleHandlerFn): FunctionHandlerDefinition;
1100
+ declare function createScheduleHandler(scheduleIdOrExpression: string, config: ScheduleHandlerConfig, handler: ScheduleHandlerFn): FunctionHandlerDefinition;
1101
+
1102
+ type CustomHandlerConfig<TInput = unknown> = {
1103
+ name?: string;
1104
+ schema?: Schema<TInput>;
1105
+ inject?: InjectionToken[];
1106
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1107
+ metadata?: Record<string, unknown>;
1108
+ };
1109
+ type CustomHandlerFn = (payload: unknown, ctx: BaseHandlerContext, ...deps: unknown[]) => Promise<unknown>;
1110
+ /**
1111
+ * Creates a function-based custom/invocable handler definition.
1112
+ *
1113
+ * Function handlers are blueprint-first — the handler name and invocation
1114
+ * binding come from the blueprint. The handler declares its dependencies,
1115
+ * an optional schema for type-safe payload validation, and the implementation.
1116
+ *
1117
+ * @example
1118
+ * ```ts
1119
+ * // With schema — payload is validated and typed before the handler runs
1120
+ * const processPayment = createCustomHandler(
1121
+ * { schema: PaymentSchema, inject: [PaymentService] },
1122
+ * async (payload, ctx, paymentService: PaymentService) => {
1123
+ * return paymentService.process(payload as PaymentInput);
1124
+ * },
1125
+ * );
1126
+ *
1127
+ * // Without schema — payload is unknown
1128
+ * const healthCheck = createCustomHandler(
1129
+ * {},
1130
+ * async () => ({ status: "ok" }),
1131
+ * );
1132
+ * ```
1133
+ */
1134
+ declare function createCustomHandler(config: CustomHandlerConfig, handler: CustomHandlerFn): FunctionHandlerDefinition;
1135
+
334
1136
  declare class HttpException extends Error {
335
1137
  readonly statusCode: number;
336
1138
  readonly details?: unknown | undefined;
@@ -382,6 +1184,8 @@ declare class GatewayTimeoutException extends HttpException {
382
1184
  constructor(message?: string, details?: unknown);
383
1185
  }
384
1186
 
1187
+ declare function routingKeyOf(handler: ResolvedHandler): string;
1188
+
385
1189
  /**
386
1190
  * Resolve a handler ID as a module reference by dynamically importing
387
1191
  * the module and matching the exported function against the registry.
@@ -399,7 +1203,159 @@ declare class GatewayTimeoutException extends HttpException {
399
1203
  * - `"app.module"` — dotted module name: tries named export split first,
400
1204
  * falls back to default export from module `app.module`
401
1205
  */
402
- declare function resolveHandlerByModuleRef(handlerId: string, registry: HandlerRegistry, baseDir: string): Promise<ResolvedHandler | null>;
1206
+ declare function resolveHandlerByModuleRef(handlerId: string, handlerType: HandlerType, registry: HandlerRegistry, baseDir: string): Promise<ResolvedHandler | null>;
1207
+
1208
+ type ModuleNode = {
1209
+ moduleClass: Type;
1210
+ ownTokens: Set<InjectionToken>;
1211
+ exports: Set<InjectionToken>;
1212
+ imports: Type[];
1213
+ controllers: Type[];
1214
+ functionHandlers: FunctionHandlerDefinition[];
1215
+ guards: (Type | GuardDefinition)[];
1216
+ providers: (Type | (Provider & {
1217
+ provide: InjectionToken;
1218
+ }))[];
1219
+ };
1220
+ type ModuleGraph = Map<Type, ModuleNode>;
1221
+ /**
1222
+ * Builds a module graph by walking the module tree depth-first, collecting
1223
+ * all metadata into a graph structure without any side effects.
1224
+ *
1225
+ * Detects circular module imports and deduplicates visited modules.
1226
+ */
1227
+ declare function buildModuleGraph(rootModule: Type): ModuleGraph;
1228
+ /**
1229
+ * Registers all providers and controllers from the module graph into the
1230
+ * DI container.
1231
+ */
1232
+ declare function registerModuleGraph(graph: ModuleGraph, container: Container): void;
1233
+
1234
+ /**
1235
+ * Scans the module graph for HTTP class handlers and function handlers,
1236
+ * registering them in the handler registry.
1237
+ */
1238
+ declare function scanHttpHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1239
+ /**
1240
+ * Scans the module graph for guard definitions (class-based and function-based),
1241
+ * registering them in the handler registry.
1242
+ */
1243
+ declare function scanHttpGuards(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1244
+ /**
1245
+ * Convenience function that builds a module graph, registers providers,
1246
+ * and scans for HTTP handlers and guards in a single call.
1247
+ */
1248
+ declare function scanModule(moduleClass: Type, container: Container, registry: HandlerRegistry): Promise<void>;
1249
+
1250
+ /**
1251
+ * Scans the module graph for WebSocket class handlers and function handlers,
1252
+ * registering them in the handler registry.
1253
+ */
1254
+ declare function scanWebSocketHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1255
+
1256
+ /**
1257
+ * Scans the module graph for Consumer class handlers and function handlers,
1258
+ * registering them in the handler registry.
1259
+ */
1260
+ declare function scanConsumerHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1261
+
1262
+ /**
1263
+ * Scans the module graph for schedule handlers — a cross-cutting scan that
1264
+ * walks ALL controllers (any class in `controllers`) looking for methods
1265
+ * decorated with `@ScheduleHandler()`. Also scans function handlers with
1266
+ * `type: "schedule"`.
1267
+ */
1268
+ declare function scanScheduleHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1269
+
1270
+ /**
1271
+ * Scans the module graph for custom/invocable handlers — a cross-cutting scan
1272
+ * that walks ALL controllers (any class in `controllers`) looking for methods
1273
+ * decorated with `@Invoke()`. Also scans function handlers with
1274
+ * `type: "custom"`.
1275
+ */
1276
+ declare function scanCustomHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1277
+
1278
+ type WebSocketPipelineOptions = {
1279
+ container: ServiceContainer;
1280
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1281
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1282
+ handlerName?: string;
1283
+ };
1284
+ declare function executeWebSocketPipeline(handler: ResolvedHandlerBase, message: WebSocketMessage, options: WebSocketPipelineOptions): Promise<void>;
1285
+
1286
+ /**
1287
+ * WebSocket sender implementation for local/container deployments.
1288
+ * Wraps the NAPI runtime's CoreWebSocketRegistry.
1289
+ */
1290
+ declare class RuntimeWebSocketSender implements WebSocketSender {
1291
+ private registry;
1292
+ constructor(registry: CoreWebSocketRegistry);
1293
+ sendMessage(connectionId: string, data: unknown, options?: WebSocketSendOptions): Promise<void>;
1294
+ }
1295
+
1296
+ type ConsumerPipelineOptions = {
1297
+ container: ServiceContainer;
1298
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1299
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1300
+ handlerName?: string;
1301
+ };
1302
+ declare function executeConsumerPipeline(handler: ResolvedHandlerBase, event: ConsumerEventInput, options: ConsumerPipelineOptions): Promise<EventResult>;
1303
+
1304
+ type SchedulePipelineOptions = {
1305
+ container: ServiceContainer;
1306
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1307
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1308
+ handlerName?: string;
1309
+ };
1310
+ declare function executeSchedulePipeline(handler: ResolvedHandlerBase, event: ScheduleEventInput$1, options: SchedulePipelineOptions): Promise<EventResult>;
1311
+
1312
+ type CustomPipelineOptions = {
1313
+ container: ServiceContainer;
1314
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1315
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1316
+ handlerName?: string;
1317
+ };
1318
+ /**
1319
+ * Execute a custom/invocable handler pipeline.
1320
+ *
1321
+ * Unlike consumer and schedule pipelines, custom handlers return raw results
1322
+ * and errors are re-thrown to the caller (not wrapped in `EventResult`).
1323
+ */
1324
+ declare function executeCustomPipeline(handler: ResolvedHandlerBase, payload: unknown, options: CustomPipelineOptions): Promise<unknown>;
1325
+
1326
+ type GuardInput = {
1327
+ token: string;
1328
+ method: string;
1329
+ path: string;
1330
+ headers: Record<string, string | string[]>;
1331
+ query: Record<string, string | string[]>;
1332
+ cookies: Record<string, string>;
1333
+ body: unknown;
1334
+ requestId: string;
1335
+ clientIp: string;
1336
+ auth: Record<string, unknown>;
1337
+ handlerName?: string;
1338
+ };
1339
+ type GuardPipelineOptions = {
1340
+ container: ServiceContainer;
1341
+ handlerMetadata?: Record<string, unknown>;
1342
+ };
1343
+ type GuardResult = {
1344
+ allowed: true;
1345
+ auth: Record<string, unknown>;
1346
+ } | {
1347
+ allowed: false;
1348
+ statusCode: number;
1349
+ message: string;
1350
+ details?: unknown;
1351
+ };
1352
+ /**
1353
+ * Executes a guard handler and returns a result indicating whether access
1354
+ * is allowed. On success, `auth` contains the data to store under
1355
+ * `request.auth.<guardName>`. On failure, `statusCode` and `message`
1356
+ * describe the rejection.
1357
+ */
1358
+ declare function executeGuardPipeline(guard: ResolvedGuard, input: GuardInput, options: GuardPipelineOptions): Promise<GuardResult>;
403
1359
 
404
1360
  declare const CONTROLLER_METADATA: unique symbol;
405
1361
  declare const HTTP_METHOD_METADATA: unique symbol;
@@ -408,9 +1364,14 @@ declare const GUARD_PROTECTEDBY_METADATA: unique symbol;
408
1364
  declare const GUARD_CUSTOM_METADATA: unique symbol;
409
1365
  declare const LAYER_METADATA: unique symbol;
410
1366
  declare const MODULE_METADATA: unique symbol;
411
- declare const INJECT_METADATA: unique symbol;
412
1367
  declare const PUBLIC_METADATA: unique symbol;
413
1368
  declare const CUSTOM_METADATA: unique symbol;
1369
+ declare const WEBSOCKET_CONTROLLER_METADATA: unique symbol;
1370
+ declare const WEBSOCKET_EVENT_METADATA: unique symbol;
1371
+ declare const CONSUMER_METADATA: unique symbol;
1372
+ declare const CONSUMER_HANDLER_METADATA: unique symbol;
1373
+ declare const SCHEDULE_HANDLER_METADATA: unique symbol;
1374
+ declare const INVOKE_METADATA: unique symbol;
414
1375
 
415
1376
  type BootstrapResult = {
416
1377
  container: Container;
@@ -428,26 +1389,35 @@ declare function flattenMultiValueRecord(record: Record<string, string[]>): Reco
428
1389
  declare function mapRuntimeRequest(request: Request): HttpRequest;
429
1390
  /** Convert SDK HttpResponse → NAPI runtime Response. */
430
1391
  declare function mapToRuntimeResponse(response: HttpResponse): Response;
1392
+ /** Convert NAPI JsWebSocketMessageInfo → SDK WebSocketMessage. */
1393
+ declare function mapWebSocketMessage(info: JsWebSocketMessageInfo): WebSocketMessage;
1394
+ /** Convert NAPI JsConsumerEventInput → SDK ConsumerEventInput. */
1395
+ declare function mapConsumerEventInput(input: JsConsumerEventInput): ConsumerEventInput;
1396
+ /** Convert NAPI JsScheduleEventInput → SDK ScheduleEventInput. */
1397
+ declare function mapScheduleEventInput(input: JsScheduleEventInput): ScheduleEventInput$1;
1398
+ /** Convert SDK EventResult → NAPI JsEventResult. */
1399
+ declare function mapToNapiEventResult(result: EventResult): JsEventResult;
431
1400
 
432
1401
  type RuntimeCallback = (err: Error | null, request: Request) => Promise<Response>;
1402
+ type WebSocketCallback = (err: Error | null, info: JsWebSocketMessageInfo) => Promise<void>;
1403
+ type ConsumerCallback = (err: Error | null, input: JsConsumerEventInput) => Promise<JsEventResult>;
1404
+ type ScheduleCallback = (err: Error | null, input: JsScheduleEventInput) => Promise<JsEventResult>;
1405
+ type CustomCallback = (err: Error | null, payload: unknown) => Promise<unknown>;
1406
+ type GuardCallback = (input: GuardInput) => Promise<GuardResult>;
433
1407
  type RuntimeBootstrapResult = {
434
1408
  registry: HandlerRegistry;
435
1409
  container: Container;
436
- /** Create a runtime-compatible handler callback for a specific route. */
437
- createRouteCallback(path: string, method: string): RuntimeCallback | null;
438
- /**
439
- * Create a runtime-compatible handler callback by handler ID.
440
- * First tries a direct registry lookup. If that fails, resolves the handler ID
441
- * as a module reference by dynamically importing the module and matching the
442
- * exported function against the registry.
443
- *
444
- * Supported formats:
445
- * - `"handlers.hello"` named export `hello` from module `handlers`
446
- * - `"handlers"` default export from module `handlers`
447
- * - `"app.module"` — dotted module name: tries named export split first,
448
- * falls back to default export from module `app.module`
449
- */
450
- createRouteCallbackById(handlerId: string, codeLocation?: string): Promise<RuntimeCallback | null>;
1410
+ createRouteCallback(method: string, path: string, handlerName?: string): RuntimeCallback | null;
1411
+ createRouteCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<RuntimeCallback | null>;
1412
+ createGuardCallback(guardName: string): GuardCallback | null;
1413
+ createWebSocketCallback(route: string, handlerName?: string): WebSocketCallback | null;
1414
+ createWebSocketCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<WebSocketCallback | null>;
1415
+ createConsumerCallback(handlerTag: string, handlerName?: string): ConsumerCallback | null;
1416
+ createConsumerCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<ConsumerCallback | null>;
1417
+ createScheduleCallback(handlerTag: string, handlerName?: string): ScheduleCallback | null;
1418
+ createScheduleCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<ScheduleCallback | null>;
1419
+ createCustomCallback(handlerName: string): CustomCallback | null;
1420
+ createCustomCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<CustomCallback | null>;
451
1421
  };
452
1422
  /**
453
1423
  * Bootstrap the user's module and return an object with per-route callback creation.
@@ -465,4 +1435,4 @@ type StartRuntimeOptions = {
465
1435
  */
466
1436
  declare function startRuntime(options?: StartRuntimeOptions): Promise<void>;
467
1437
 
468
- export { APP_CONFIG, Action, Auth, BadGatewayException, BadRequestException, Body, type BootstrapResult, CONTROLLER_METADATA, CUSTOM_METADATA, CelerityApplication, CelerityFactory, ConflictException, Container, Controller, type ControllerMetadata, Cookies, type CreateOptions, Delete, ForbiddenException, GUARD_CUSTOM_METADATA, GUARD_PROTECTEDBY_METADATA, GatewayTimeoutException, Get, GoneException, Guard, HTTP_METHOD_METADATA, HandlerMetadataStore, HandlerRegistry, Head, Headers, HttpException, type HttpHandlerConfig, type HttpHandlerContext, type HttpHandlerRequest, INJECT_METADATA, Inject, Injectable, InternalServerErrorException, LAYER_METADATA, MODULE_METADATA, MethodNotAllowedException, type MockRequestOptions, Module, type ModuleGraph, type ModuleNode, NotAcceptableException, NotFoundException, NotImplementedException, Options, PUBLIC_METADATA, Param, type ParamMetadata, type ParamType, Patch, type PipelineOptions, Post, ProtectedBy, Public, Put, Query, ROUTE_PATH_METADATA, RUNTIME_APP, Req, RequestId, type ResolvedHandler, type RuntimeBootstrapResult, type ServerlessAdapter, ServerlessApplication, type ServerlessHandler, ServiceUnavailableException, SetMetadata, type StartRuntimeOptions, TestingApplication, TooManyRequestsException, UnauthorizedException, UnprocessableEntityException, UseLayer, UseLayers, type ValidationSchemas, bootstrap, bootstrapForRuntime, buildModuleGraph, createDefaultSystemLayers, createHttpHandler, discoverModule, disposeLayers, executeHandlerPipeline, flattenMultiValueRecord, getClassDependencyTokens, getProviderDependencyTokens, httpDelete, httpGet, httpPatch, httpPost, httpPut, mapRuntimeRequest, mapToRuntimeResponse, mockRequest, registerModuleGraph, resolveHandlerByModuleRef, runLayerPipeline, startRuntime, tokenToString, validate };
1438
+ export { APP_CONFIG, Action, Auth, BadGatewayException, BadRequestException, Body, type BootstrapResult, CONSUMER_HANDLER_METADATA, CONSUMER_METADATA, CONTROLLER_METADATA, CUSTOM_METADATA, CelerityApplication, CelerityFactory, ConflictException, ConnectionId, Consumer, type ConsumerHandlerConfig, type ConsumerHandlerMetadata, type ConsumerMetadata, type ConsumerPipelineOptions, ConsumerTraceContext, Container, Controller, type ControllerMetadata, Cookies, type CreateOptions, type CustomHandlerConfig, type CustomPipelineOptions, Delete, EventInput, EventType, ForbiddenException, GUARD_CUSTOM_METADATA, GUARD_PROTECTEDBY_METADATA, GatewayTimeoutException, Get, GoneException, Guard, type GuardConfig, type GuardContext, type GuardHandlerFn, type GuardInput, type GuardPipelineOptions, type GuardRequest, type GuardResult, HTTP_METHOD_METADATA, HandlerMetadataStore, HandlerRegistry, Head, Headers, HttpException, type HttpFunctionContext, type HttpHandlerConfig, type HttpHandlerRequest, INVOKE_METADATA, Inject, Injectable, InternalServerErrorException, Invoke, InvokeContext, type InvokeMetadata, LAYER_METADATA, MODULE_METADATA, MessageBody, MessageHandler, MessageId, Messages, MethodNotAllowedException, type MockConsumerEventOptions, type MockConsumerMessage, type MockRequestOptions, type MockScheduleEventOptions, type MockWebSocketMessageOptions, Module, type ModuleGraph, type ModuleNode, NotAcceptableException, NotFoundException, NotImplementedException, OnConnect, OnDisconnect, OnMessage, Options, PUBLIC_METADATA, Param, type ParamMetadata, type ParamType, Patch, Payload, type PipelineOptions, Post, ProtectedBy, Public, Put, Query, ROUTE_PATH_METADATA, RUNTIME_APP, Req, RequestContext, RequestId, type ResolvedConsumerHandler, type ResolvedCustomHandler, type ResolvedGuard, type ResolvedHandler, type ResolvedHandlerBase, type ResolvedHttpHandler, type ResolvedScheduleHandler, type ResolvedWebSocketHandler, type RuntimeBootstrapResult, RuntimeWebSocketSender, SCHEDULE_HANDLER_METADATA, ScheduleEventInput as ScheduleEventInputParam, ScheduleExpression, ScheduleHandler, type ScheduleHandlerConfig, type ScheduleHandlerMetadata, ScheduleId, ScheduleInput, type SchedulePipelineOptions, type ServerlessAdapter, ServerlessApplication, type ServerlessHandler, ServiceUnavailableException, SetMetadata, type StartRuntimeOptions, TestingApplication, Token, TooManyRequestsException, UnauthorizedException, UnprocessableEntityException, UseLayer, UseLayers, UseResource, UseResources, type ValidationSchemas, Vendor, WEBSOCKET_CONTROLLER_METADATA, WEBSOCKET_EVENT_METADATA, WebSocketController, type WebSocketEventMetadata, type WebSocketHandlerConfig, type WebSocketPipelineOptions, bootstrap, bootstrapForRuntime, buildModuleGraph, createConsumerHandler, createCustomHandler, createDefaultSystemLayers, createGuard, createHttpHandler, createScheduleHandler, createWebSocketHandler, discoverModule, disposeLayers, executeConsumerPipeline, executeCustomPipeline, executeGuardPipeline, executeHttpPipeline, executeSchedulePipeline, executeWebSocketPipeline, flattenMultiValueRecord, getClassDependencyTokens, getProviderDependencyTokens, httpDelete, httpGet, httpPatch, httpPost, httpPut, mapConsumerEventInput, mapRuntimeRequest, mapScheduleEventInput, mapToNapiEventResult, mapToRuntimeResponse, mapWebSocketMessage, mockConsumerEvent, mockRequest, mockScheduleEvent, mockWebSocketMessage, registerModuleGraph, resolveHandlerByModuleRef, routingKeyOf, runLayerPipeline, scanConsumerHandlers, scanCustomHandlers, scanHttpGuards, scanHttpHandlers, scanModule, scanScheduleHandlers, scanWebSocketHandlers, startRuntime, tokenToString, validate };