@celerity-sdk/core 0.3.1 → 0.5.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.cts 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
+ source?: 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 source - Optional blueprint resource name that tells the deploy engine
447
+ * which blueprint-defined consumer resource this handler should be wired to.
448
+ * Does not create infrastructure — the blueprint defines the actual source.
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * @Consumer("ordersConsumer")
453
+ * class OrderConsumer {
454
+ * @MessageHandler()
455
+ * async process(@Messages(OrderSchema) messages: ValidatedConsumerMessage<Order>[]): Promise<EventResult> {
456
+ * // ...
457
+ * }
458
+ * }
459
+ * ```
460
+ */
461
+ declare function Consumer(source?: 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
+ source?: string;
521
+ schedule?: string;
522
+ };
523
+ type ScheduleHandlerOptions = {
524
+ source?: 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 → `source` blueprint resource name hint for deploy engine
542
+ * - Object → explicit `{ source?, schedule? }`
543
+ *
544
+ * @example
545
+ * ```ts
546
+ * @Controller()
547
+ * class MaintenanceTasks {
548
+ * @ScheduleHandler("dailyCleanup")
549
+ * async cleanup(@ScheduleInput() input: unknown): Promise<EventResult> {
550
+ * // source hint — matches blueprint resource name, 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({ source: "weeklyReport", 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(sourceOrExpression: 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,82 @@ 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;
755
+ /** The class to lazily resolve via container on first invocation. */
756
+ controllerClass?: Type;
166
757
  isFunctionHandler?: boolean;
167
758
  injectTokens?: InjectionToken[];
759
+ layers: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
760
+ paramMetadata: ParamMetadata[];
761
+ customMetadata: Record<string, unknown>;
168
762
  };
169
- type PipelineOptions = {
170
- container: ServiceContainer;
171
- systemLayers?: (CelerityLayer | Type<CelerityLayer>)[];
172
- appLayers?: (CelerityLayer | Type<CelerityLayer>)[];
763
+ type GuardableFields = {
764
+ protectedBy: string[];
765
+ isPublic: boolean;
173
766
  };
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
- }))[];
767
+ type ResolvedHttpHandler = ResolvedHandlerBase & GuardableFields & {
768
+ type: "http";
769
+ path?: string;
770
+ method?: HttpMethod;
771
+ };
772
+ type ResolvedWebSocketHandler = ResolvedHandlerBase & GuardableFields & {
773
+ type: "websocket";
774
+ route: string;
775
+ };
776
+ type ResolvedConsumerHandler = ResolvedHandlerBase & {
777
+ type: "consumer";
778
+ handlerTag: string;
779
+ };
780
+ type ResolvedScheduleHandler = ResolvedHandlerBase & {
781
+ type: "schedule";
782
+ handlerTag: string;
783
+ };
784
+ type ResolvedCustomHandler = ResolvedHandlerBase & {
785
+ type: "custom";
786
+ name: string;
787
+ };
788
+ type ResolvedHandler = ResolvedHttpHandler | ResolvedWebSocketHandler | ResolvedConsumerHandler | ResolvedScheduleHandler | ResolvedCustomHandler;
789
+ type ResolvedGuard = {
790
+ name: string;
791
+ handlerFn: (...args: unknown[]) => unknown;
792
+ handlerInstance?: object;
793
+ /** The guard class to lazily resolve via container on first invocation. */
794
+ guardClass?: Type;
795
+ paramMetadata: ParamMetadata[];
796
+ customMetadata: Record<string, unknown>;
797
+ injectTokens?: InjectionToken[];
798
+ isFunctionGuard?: boolean;
186
799
  };
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
800
 
201
801
  declare class HandlerRegistry {
202
- private handlers;
203
- getHandler(path: string, method: string): ResolvedHandler | undefined;
204
- getHandlerById(id: string): ResolvedHandler | undefined;
802
+ private byType;
803
+ private exactLookup;
804
+ private byId;
805
+ private guards;
806
+ register(handler: ResolvedHandler): void;
807
+ getHandler(type: "http", routingKey: string): ResolvedHttpHandler | undefined;
808
+ getHandler(type: "websocket", routingKey: string): ResolvedWebSocketHandler | undefined;
809
+ getHandler(type: "consumer", routingKey: string): ResolvedConsumerHandler | undefined;
810
+ getHandler(type: "schedule", routingKey: string): ResolvedScheduleHandler | undefined;
811
+ getHandler(type: "custom", routingKey: string): ResolvedCustomHandler | undefined;
812
+ getHandlerById<T extends HandlerType>(type: T, id: string): Extract<ResolvedHandler, {
813
+ type: T;
814
+ }> | undefined;
815
+ getHandlersByType<T extends HandlerType>(type: T): Extract<ResolvedHandler, {
816
+ type: T;
817
+ }>[];
205
818
  getAllHandlers(): ResolvedHandler[];
206
- populateFromGraph(graph: ModuleGraph, container: Container): Promise<void>;
207
- scanModule(moduleClass: Type, container: Container): Promise<void>;
208
- private registerClassHandler;
209
- private registerFunctionHandler;
819
+ registerGuard(guard: ResolvedGuard): void;
820
+ getGuard(name: string): ResolvedGuard | undefined;
821
+ getAllGuards(): ResolvedGuard[];
822
+ /**
823
+ * HTTP routing uses path-pattern matching: `"GET /items/{id}"` matches `"GET /items/42"`.
824
+ * The routing key format is `"METHOD path"` (e.g., `"GET /items/{id}"`).
825
+ */
826
+ private findHttpHandler;
210
827
  }
211
828
 
212
829
  declare class CelerityApplication {
@@ -224,9 +841,21 @@ declare class CelerityApplication {
224
841
  getAppLayers(): (CelerityLayer | Type<CelerityLayer>)[];
225
842
  }
226
843
 
844
+ type PipelineOptions = {
845
+ container: ServiceContainer;
846
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
847
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
848
+ handlerName?: string;
849
+ };
850
+ declare function executeHttpPipeline(handler: ResolvedHandlerBase, request: HttpRequest, options: PipelineOptions): Promise<HttpResponse>;
851
+
227
852
  type ServerlessHandler = (event: unknown, context: unknown) => Promise<unknown>;
228
853
  interface ServerlessAdapter {
229
- createHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
854
+ createHttpHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
855
+ createWebSocketHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
856
+ createConsumerHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
857
+ createScheduleHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
858
+ createCustomHandler(registry: HandlerRegistry, options: PipelineOptions): ServerlessHandler;
230
859
  }
231
860
 
232
861
  declare class ServerlessApplication {
@@ -237,7 +866,8 @@ declare class ServerlessApplication {
237
866
  private appLayers;
238
867
  private handler;
239
868
  constructor(registry: HandlerRegistry, container: Container, adapter: ServerlessAdapter, systemLayers?: (CelerityLayer | Type<CelerityLayer>)[], appLayers?: (CelerityLayer | Type<CelerityLayer>)[]);
240
- start(): Promise<ServerlessHandler>;
869
+ createHandler(type: HandlerType): ServerlessHandler;
870
+ start(type?: HandlerType): Promise<ServerlessHandler>;
241
871
  close(): Promise<void>;
242
872
  getHandler(): ServerlessHandler;
243
873
  getContainer(): Container;
@@ -250,7 +880,11 @@ declare class TestingApplication {
250
880
  private systemLayers;
251
881
  private appLayers;
252
882
  constructor(registry: HandlerRegistry, container: Container, systemLayers?: (CelerityLayer | Type<CelerityLayer>)[], appLayers?: (CelerityLayer | Type<CelerityLayer>)[]);
253
- inject(request: HttpRequest): Promise<HttpResponse>;
883
+ injectHttp(request: HttpRequest): Promise<HttpResponse>;
884
+ injectWebSocket(route: string, message: WebSocketMessage): Promise<void>;
885
+ injectConsumer(handlerTag: string, event: ConsumerEventInput): Promise<EventResult>;
886
+ injectSchedule(handlerTag: string, event: ScheduleEventInput$1): Promise<EventResult>;
887
+ injectCustom(name: string, payload?: unknown): Promise<unknown>;
254
888
  getContainer(): Container;
255
889
  getRegistry(): HandlerRegistry;
256
890
  }
@@ -265,6 +899,39 @@ type MockRequestOptions = {
265
899
  clientIp?: string;
266
900
  };
267
901
  declare function mockRequest(method: HttpMethod, path: string, options?: MockRequestOptions): HttpRequest;
902
+ type MockWebSocketMessageOptions = {
903
+ messageType?: WebSocketMessageType;
904
+ eventType?: WebSocketEventType;
905
+ connectionId?: string;
906
+ messageId?: string;
907
+ jsonBody?: unknown;
908
+ binaryBody?: Buffer;
909
+ traceContext?: Record<string, string> | null;
910
+ };
911
+ declare function mockWebSocketMessage(options?: MockWebSocketMessageOptions): WebSocketMessage;
912
+ type MockConsumerMessage = {
913
+ messageId?: string;
914
+ body: string;
915
+ source?: string;
916
+ sourceType?: string;
917
+ sourceName?: string;
918
+ eventType?: string;
919
+ messageAttributes?: MessageAttributes;
920
+ };
921
+ type MockConsumerEventOptions = {
922
+ vendor?: unknown;
923
+ traceContext?: Record<string, string> | null;
924
+ };
925
+ declare function mockConsumerEvent(handlerTag: string, messages: MockConsumerMessage[], options?: MockConsumerEventOptions): ConsumerEventInput;
926
+ type MockScheduleEventOptions = {
927
+ scheduleId?: string;
928
+ messageId?: string;
929
+ schedule?: string;
930
+ input?: unknown;
931
+ vendor?: unknown;
932
+ traceContext?: Record<string, string> | null;
933
+ };
934
+ declare function mockScheduleEvent(handlerTag: string, options?: MockScheduleEventOptions): ScheduleEventInput$1;
268
935
 
269
936
  type CreateOptions = {
270
937
  adapter?: ServerlessAdapter;
@@ -294,7 +961,7 @@ type HttpHandlerRequest<TBody = unknown> = {
294
961
  userAgent: string | null;
295
962
  contentType: string | null;
296
963
  };
297
- type HttpHandlerContext = {
964
+ type HttpFunctionContext = {
298
965
  requestId: string;
299
966
  requestTime: string;
300
967
  metadata: HandlerMetadata;
@@ -318,7 +985,7 @@ type HttpHandlerConfig<TBody = unknown> = {
318
985
  metadata?: Record<string, unknown>;
319
986
  };
320
987
  type HttpHandlerOptions<TBody = unknown> = Omit<HttpHandlerConfig<TBody>, "path" | "method">;
321
- type HttpHandlerFn<TBody = unknown> = (req: HttpHandlerRequest<TBody>, ctx: HttpHandlerContext, ...deps: unknown[]) => unknown;
988
+ type HttpHandlerFn<TBody = unknown> = (req: HttpHandlerRequest<TBody>, ctx: HttpFunctionContext, ...deps: unknown[]) => unknown;
322
989
  declare function createHttpHandler<TBody = unknown>(config: HttpHandlerConfig<TBody>, handler: HttpHandlerFn<TBody>): FunctionHandlerDefinition;
323
990
  declare function httpGet(path: string, handler: HttpHandlerFn): FunctionHandlerDefinition;
324
991
  declare function httpGet(path: string, options: HttpHandlerOptions, handler: HttpHandlerFn): FunctionHandlerDefinition;
@@ -331,6 +998,145 @@ declare function httpPatch<TBody = unknown>(path: string, options: HttpHandlerOp
331
998
  declare function httpDelete(path: string, handler: HttpHandlerFn): FunctionHandlerDefinition;
332
999
  declare function httpDelete(path: string, options: HttpHandlerOptions, handler: HttpHandlerFn): FunctionHandlerDefinition;
333
1000
 
1001
+ type GuardConfig = {
1002
+ name?: string;
1003
+ inject?: InjectionToken[];
1004
+ metadata?: Record<string, unknown>;
1005
+ };
1006
+ /**
1007
+ * The request context provided to a guard handler.
1008
+ * Mirrors the Rust runtime's `AuthGuardValidateInput` + `RequestInfo`.
1009
+ */
1010
+ type GuardRequest = {
1011
+ token: string;
1012
+ headers: Record<string, string | string[]>;
1013
+ query: Record<string, string | string[]>;
1014
+ cookies: Record<string, string>;
1015
+ body: unknown;
1016
+ requestId: string;
1017
+ clientIp: string;
1018
+ };
1019
+ type GuardContext = {
1020
+ metadata: HandlerMetadata;
1021
+ container: ServiceContainer;
1022
+ logger?: CelerityLogger;
1023
+ /**
1024
+ * Claims accumulated from preceding guards in the chain.
1025
+ * Keyed by guard name (e.g. `{ jwt: { sub: "user-1", ... } }`).
1026
+ * Empty object for the first guard in the chain.
1027
+ */
1028
+ auth: Record<string, unknown>;
1029
+ };
1030
+ /**
1031
+ * Guard handler function signature.
1032
+ * Return the claims object to attach to `request.auth.<guardName>`,
1033
+ * or throw `ForbiddenException`/`UnauthorizedException` to reject.
1034
+ */
1035
+ type GuardHandlerFn = (req: GuardRequest, ctx: GuardContext, ...deps: unknown[]) => unknown;
1036
+ declare function createGuard(config: GuardConfig, handler: GuardHandlerFn): GuardDefinition;
1037
+
1038
+ type WebSocketHandlerConfig = {
1039
+ route?: string;
1040
+ protectedBy?: string[];
1041
+ schema?: Schema;
1042
+ inject?: InjectionToken[];
1043
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1044
+ metadata?: Record<string, unknown>;
1045
+ };
1046
+ type WebSocketHandlerFn = (message: WebSocketMessage, ctx: WebSocketHandlerContext, ...deps: unknown[]) => Promise<void> | void;
1047
+ declare function createWebSocketHandler(config: WebSocketHandlerConfig, handler: WebSocketHandlerFn): FunctionHandlerDefinition;
1048
+
1049
+ type ConsumerHandlerConfig = {
1050
+ route?: string;
1051
+ messageSchema?: Schema;
1052
+ inject?: InjectionToken[];
1053
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1054
+ metadata?: Record<string, unknown>;
1055
+ };
1056
+ type ConsumerHandlerFn = (event: ConsumerEventInput, ctx: ConsumerHandlerContext, ...deps: unknown[]) => Promise<EventResult>;
1057
+ declare function createConsumerHandler(config: ConsumerHandlerConfig, handler: ConsumerHandlerFn): FunctionHandlerDefinition;
1058
+
1059
+ type ScheduleHandlerConfig<T = unknown> = {
1060
+ source?: string;
1061
+ schedule?: string;
1062
+ schema?: Schema<T>;
1063
+ inject?: InjectionToken[];
1064
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1065
+ metadata?: Record<string, unknown>;
1066
+ };
1067
+ type ScheduleHandlerFn = (event: ScheduleEventInput$1, ctx: ScheduleHandlerContext, ...deps: unknown[]) => Promise<EventResult>;
1068
+ /**
1069
+ * Creates a function-based schedule handler definition.
1070
+ *
1071
+ * Function handlers are blueprint-first — the schedule expression, timezone,
1072
+ * and handler binding are all defined in the blueprint. The handler declares
1073
+ * its dependencies and provides the task logic.
1074
+ *
1075
+ * @example
1076
+ * ```ts
1077
+ * // Minimal — blueprint defines everything
1078
+ * const dailyCleanup = createScheduleHandler(
1079
+ * { inject: [CleanupService] },
1080
+ * async (event, ctx, cleanupService: CleanupService) => {
1081
+ * await cleanupService.run();
1082
+ * return { success: true };
1083
+ * },
1084
+ * );
1085
+ *
1086
+ * // With source hint for deploy engine auto-wiring
1087
+ * const weeklyReport = createScheduleHandler("weeklyReport", {
1088
+ * inject: [ReportService],
1089
+ * }, async (event, ctx, reportService: ReportService) => {
1090
+ * await reportService.generate();
1091
+ * return { success: true };
1092
+ * });
1093
+ *
1094
+ * // With expression for prototyping / single-environment apps
1095
+ * const hourlySync = createScheduleHandler("rate(1 hour)", {
1096
+ * inject: [SyncService],
1097
+ * }, async (event, ctx, syncService: SyncService) => {
1098
+ * await syncService.run();
1099
+ * return { success: true };
1100
+ * });
1101
+ * ```
1102
+ */
1103
+ declare function createScheduleHandler(config: ScheduleHandlerConfig, handler: ScheduleHandlerFn): FunctionHandlerDefinition;
1104
+ declare function createScheduleHandler(sourceOrExpression: string, config: ScheduleHandlerConfig, handler: ScheduleHandlerFn): FunctionHandlerDefinition;
1105
+
1106
+ type CustomHandlerConfig<TInput = unknown> = {
1107
+ name?: string;
1108
+ schema?: Schema<TInput>;
1109
+ inject?: InjectionToken[];
1110
+ layers?: (CelerityLayer | Type<CelerityLayer>)[];
1111
+ metadata?: Record<string, unknown>;
1112
+ };
1113
+ type CustomHandlerFn = (payload: unknown, ctx: BaseHandlerContext, ...deps: unknown[]) => Promise<unknown>;
1114
+ /**
1115
+ * Creates a function-based custom/invocable handler definition.
1116
+ *
1117
+ * Function handlers are blueprint-first — the handler name and invocation
1118
+ * binding come from the blueprint. The handler declares its dependencies,
1119
+ * an optional schema for type-safe payload validation, and the implementation.
1120
+ *
1121
+ * @example
1122
+ * ```ts
1123
+ * // With schema — payload is validated and typed before the handler runs
1124
+ * const processPayment = createCustomHandler(
1125
+ * { schema: PaymentSchema, inject: [PaymentService] },
1126
+ * async (payload, ctx, paymentService: PaymentService) => {
1127
+ * return paymentService.process(payload as PaymentInput);
1128
+ * },
1129
+ * );
1130
+ *
1131
+ * // Without schema — payload is unknown
1132
+ * const healthCheck = createCustomHandler(
1133
+ * {},
1134
+ * async () => ({ status: "ok" }),
1135
+ * );
1136
+ * ```
1137
+ */
1138
+ declare function createCustomHandler(config: CustomHandlerConfig, handler: CustomHandlerFn): FunctionHandlerDefinition;
1139
+
334
1140
  declare class HttpException extends Error {
335
1141
  readonly statusCode: number;
336
1142
  readonly details?: unknown | undefined;
@@ -382,6 +1188,8 @@ declare class GatewayTimeoutException extends HttpException {
382
1188
  constructor(message?: string, details?: unknown);
383
1189
  }
384
1190
 
1191
+ declare function routingKeyOf(handler: ResolvedHandler): string;
1192
+
385
1193
  /**
386
1194
  * Resolve a handler ID as a module reference by dynamically importing
387
1195
  * the module and matching the exported function against the registry.
@@ -399,7 +1207,159 @@ declare class GatewayTimeoutException extends HttpException {
399
1207
  * - `"app.module"` — dotted module name: tries named export split first,
400
1208
  * falls back to default export from module `app.module`
401
1209
  */
402
- declare function resolveHandlerByModuleRef(handlerId: string, registry: HandlerRegistry, baseDir: string): Promise<ResolvedHandler | null>;
1210
+ declare function resolveHandlerByModuleRef(handlerId: string, handlerType: HandlerType, registry: HandlerRegistry, baseDir: string): Promise<ResolvedHandler | null>;
1211
+
1212
+ type ModuleNode = {
1213
+ moduleClass: Type;
1214
+ ownTokens: Set<InjectionToken>;
1215
+ exports: Set<InjectionToken>;
1216
+ imports: Type[];
1217
+ controllers: Type[];
1218
+ functionHandlers: FunctionHandlerDefinition[];
1219
+ guards: (Type | GuardDefinition)[];
1220
+ providers: (Type | (Provider & {
1221
+ provide: InjectionToken;
1222
+ }))[];
1223
+ };
1224
+ type ModuleGraph = Map<Type, ModuleNode>;
1225
+ /**
1226
+ * Builds a module graph by walking the module tree depth-first, collecting
1227
+ * all metadata into a graph structure without any side effects.
1228
+ *
1229
+ * Detects circular module imports and deduplicates visited modules.
1230
+ */
1231
+ declare function buildModuleGraph(rootModule: Type): ModuleGraph;
1232
+ /**
1233
+ * Registers all providers and controllers from the module graph into the
1234
+ * DI container.
1235
+ */
1236
+ declare function registerModuleGraph(graph: ModuleGraph, container: Container): void;
1237
+
1238
+ /**
1239
+ * Scans the module graph for HTTP class handlers and function handlers,
1240
+ * registering them in the handler registry.
1241
+ */
1242
+ declare function scanHttpHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1243
+ /**
1244
+ * Scans the module graph for guard definitions (class-based and function-based),
1245
+ * registering them in the handler registry.
1246
+ */
1247
+ declare function scanHttpGuards(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1248
+ /**
1249
+ * Convenience function that builds a module graph, registers providers,
1250
+ * and scans for HTTP handlers and guards in a single call.
1251
+ */
1252
+ declare function scanModule(moduleClass: Type, container: Container, registry: HandlerRegistry): Promise<void>;
1253
+
1254
+ /**
1255
+ * Scans the module graph for WebSocket class handlers and function handlers,
1256
+ * registering them in the handler registry.
1257
+ */
1258
+ declare function scanWebSocketHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1259
+
1260
+ /**
1261
+ * Scans the module graph for Consumer class handlers and function handlers,
1262
+ * registering them in the handler registry.
1263
+ */
1264
+ declare function scanConsumerHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1265
+
1266
+ /**
1267
+ * Scans the module graph for schedule handlers — a cross-cutting scan that
1268
+ * walks ALL controllers (any class in `controllers`) looking for methods
1269
+ * decorated with `@ScheduleHandler()`. Also scans function handlers with
1270
+ * `type: "schedule"`.
1271
+ */
1272
+ declare function scanScheduleHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1273
+
1274
+ /**
1275
+ * Scans the module graph for custom/invocable handlers — a cross-cutting scan
1276
+ * that walks ALL controllers (any class in `controllers`) looking for methods
1277
+ * decorated with `@Invoke()`. Also scans function handlers with
1278
+ * `type: "custom"`.
1279
+ */
1280
+ declare function scanCustomHandlers(graph: ModuleGraph, container: Container, registry: HandlerRegistry): Promise<void>;
1281
+
1282
+ type WebSocketPipelineOptions = {
1283
+ container: ServiceContainer;
1284
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1285
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1286
+ handlerName?: string;
1287
+ };
1288
+ declare function executeWebSocketPipeline(handler: ResolvedHandlerBase, message: WebSocketMessage, options: WebSocketPipelineOptions): Promise<void>;
1289
+
1290
+ /**
1291
+ * WebSocket sender implementation for local/container deployments.
1292
+ * Wraps the NAPI runtime's CoreWebSocketRegistry.
1293
+ */
1294
+ declare class RuntimeWebSocketSender implements WebSocketSender {
1295
+ private registry;
1296
+ constructor(registry: CoreWebSocketRegistry);
1297
+ sendMessage(connectionId: string, data: unknown, options?: WebSocketSendOptions): Promise<void>;
1298
+ }
1299
+
1300
+ type ConsumerPipelineOptions = {
1301
+ container: ServiceContainer;
1302
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1303
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1304
+ handlerName?: string;
1305
+ };
1306
+ declare function executeConsumerPipeline(handler: ResolvedHandlerBase, event: ConsumerEventInput, options: ConsumerPipelineOptions): Promise<EventResult>;
1307
+
1308
+ type SchedulePipelineOptions = {
1309
+ container: ServiceContainer;
1310
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1311
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1312
+ handlerName?: string;
1313
+ };
1314
+ declare function executeSchedulePipeline(handler: ResolvedHandlerBase, event: ScheduleEventInput$1, options: SchedulePipelineOptions): Promise<EventResult>;
1315
+
1316
+ type CustomPipelineOptions = {
1317
+ container: ServiceContainer;
1318
+ systemLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1319
+ appLayers?: (CelerityLayer<BaseHandlerContext> | Type<CelerityLayer<BaseHandlerContext>>)[];
1320
+ handlerName?: string;
1321
+ };
1322
+ /**
1323
+ * Execute a custom/invocable handler pipeline.
1324
+ *
1325
+ * Unlike consumer and schedule pipelines, custom handlers return raw results
1326
+ * and errors are re-thrown to the caller (not wrapped in `EventResult`).
1327
+ */
1328
+ declare function executeCustomPipeline(handler: ResolvedHandlerBase, payload: unknown, options: CustomPipelineOptions): Promise<unknown>;
1329
+
1330
+ type GuardInput = {
1331
+ token: string;
1332
+ method: string;
1333
+ path: string;
1334
+ headers: Record<string, string | string[]>;
1335
+ query: Record<string, string | string[]>;
1336
+ cookies: Record<string, string>;
1337
+ body: unknown;
1338
+ requestId: string;
1339
+ clientIp: string;
1340
+ auth: Record<string, unknown>;
1341
+ handlerName?: string;
1342
+ };
1343
+ type GuardPipelineOptions = {
1344
+ container: ServiceContainer;
1345
+ handlerMetadata?: Record<string, unknown>;
1346
+ };
1347
+ type GuardResult = {
1348
+ allowed: true;
1349
+ auth: Record<string, unknown>;
1350
+ } | {
1351
+ allowed: false;
1352
+ statusCode: number;
1353
+ message: string;
1354
+ details?: unknown;
1355
+ };
1356
+ /**
1357
+ * Executes a guard handler and returns a result indicating whether access
1358
+ * is allowed. On success, `auth` contains the data to store under
1359
+ * `request.auth.<guardName>`. On failure, `statusCode` and `message`
1360
+ * describe the rejection.
1361
+ */
1362
+ declare function executeGuardPipeline(guard: ResolvedGuard, input: GuardInput, options: GuardPipelineOptions): Promise<GuardResult>;
403
1363
 
404
1364
  declare const CONTROLLER_METADATA: unique symbol;
405
1365
  declare const HTTP_METHOD_METADATA: unique symbol;
@@ -408,9 +1368,14 @@ declare const GUARD_PROTECTEDBY_METADATA: unique symbol;
408
1368
  declare const GUARD_CUSTOM_METADATA: unique symbol;
409
1369
  declare const LAYER_METADATA: unique symbol;
410
1370
  declare const MODULE_METADATA: unique symbol;
411
- declare const INJECT_METADATA: unique symbol;
412
1371
  declare const PUBLIC_METADATA: unique symbol;
413
1372
  declare const CUSTOM_METADATA: unique symbol;
1373
+ declare const WEBSOCKET_CONTROLLER_METADATA: unique symbol;
1374
+ declare const WEBSOCKET_EVENT_METADATA: unique symbol;
1375
+ declare const CONSUMER_METADATA: unique symbol;
1376
+ declare const CONSUMER_HANDLER_METADATA: unique symbol;
1377
+ declare const SCHEDULE_HANDLER_METADATA: unique symbol;
1378
+ declare const INVOKE_METADATA: unique symbol;
414
1379
 
415
1380
  type BootstrapResult = {
416
1381
  container: Container;
@@ -428,26 +1393,35 @@ declare function flattenMultiValueRecord(record: Record<string, string[]>): Reco
428
1393
  declare function mapRuntimeRequest(request: Request): HttpRequest;
429
1394
  /** Convert SDK HttpResponse → NAPI runtime Response. */
430
1395
  declare function mapToRuntimeResponse(response: HttpResponse): Response;
1396
+ /** Convert NAPI JsWebSocketMessageInfo → SDK WebSocketMessage. */
1397
+ declare function mapWebSocketMessage(info: JsWebSocketMessageInfo): WebSocketMessage;
1398
+ /** Convert NAPI JsConsumerEventInput → SDK ConsumerEventInput. */
1399
+ declare function mapConsumerEventInput(input: JsConsumerEventInput): ConsumerEventInput;
1400
+ /** Convert NAPI JsScheduleEventInput → SDK ScheduleEventInput. */
1401
+ declare function mapScheduleEventInput(input: JsScheduleEventInput): ScheduleEventInput$1;
1402
+ /** Convert SDK EventResult → NAPI JsEventResult. */
1403
+ declare function mapToNapiEventResult(result: EventResult): JsEventResult;
431
1404
 
432
1405
  type RuntimeCallback = (err: Error | null, request: Request) => Promise<Response>;
1406
+ type WebSocketCallback = (err: Error | null, info: JsWebSocketMessageInfo) => Promise<void>;
1407
+ type ConsumerCallback = (err: Error | null, input: JsConsumerEventInput) => Promise<JsEventResult>;
1408
+ type ScheduleCallback = (err: Error | null, input: JsScheduleEventInput) => Promise<JsEventResult>;
1409
+ type CustomCallback = (err: Error | null, payload: unknown) => Promise<unknown>;
1410
+ type GuardCallback = (input: GuardInput) => Promise<GuardResult>;
433
1411
  type RuntimeBootstrapResult = {
434
1412
  registry: HandlerRegistry;
435
1413
  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>;
1414
+ createRouteCallback(method: string, path: string, handlerName?: string): RuntimeCallback | null;
1415
+ createRouteCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<RuntimeCallback | null>;
1416
+ createGuardCallback(guardName: string): GuardCallback | null;
1417
+ createWebSocketCallback(route: string, handlerName?: string): WebSocketCallback | null;
1418
+ createWebSocketCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<WebSocketCallback | null>;
1419
+ createConsumerCallback(handlerTag: string, handlerName?: string): ConsumerCallback | null;
1420
+ createConsumerCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<ConsumerCallback | null>;
1421
+ createScheduleCallback(handlerTag: string, handlerName?: string): ScheduleCallback | null;
1422
+ createScheduleCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<ScheduleCallback | null>;
1423
+ createCustomCallback(handlerName: string): CustomCallback | null;
1424
+ createCustomCallbackById(handlerId: string, codeLocation?: string, handlerName?: string): Promise<CustomCallback | null>;
451
1425
  };
452
1426
  /**
453
1427
  * Bootstrap the user's module and return an object with per-route callback creation.
@@ -465,4 +1439,4 @@ type StartRuntimeOptions = {
465
1439
  */
466
1440
  declare function startRuntime(options?: StartRuntimeOptions): Promise<void>;
467
1441
 
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 };
1442
+ 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 };