@celerity-sdk/cli 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/README.md CHANGED
@@ -24,6 +24,23 @@ The Go-based Celerity CLI invokes this tool during the build phase to merge code
24
24
  2. **Serialization** (`serializeManifest`) - converts scanned metadata into a structured manifest with handler entries, annotations, and a dependency graph.
25
25
  3. **Validation** (`validateScannedDependencies`) - checks that all provider dependencies are resolvable, reporting diagnostics for missing tokens.
26
26
 
27
+ ## Supported Handler Types
28
+
29
+ The extraction tool produces manifest entries for both **class-based** (decorator-driven) and **function-based** (blueprint-driven) handlers across all handler types:
30
+
31
+ | Handler Type | Class Decorator | Function Type | Description |
32
+ |---|---|---|---|
33
+ | HTTP | `@Get`, `@Post`, `@Put`, `@Patch`, `@Delete` | `"http"` | REST API route handlers |
34
+ | WebSocket | `@OnConnect`, `@OnDisconnect`, `@OnMessage` | `"websocket"` | WebSocket event handlers |
35
+ | Consumer | `@ConsumerHandler` | `"consumer"` | Queue/topic message consumers |
36
+ | Schedule | `@ScheduleHandler` | `"schedule"` | Cron/rate scheduled handlers |
37
+ | Custom | `@Invoke` | `"custom"` | Direct invocation handlers |
38
+ | Guard | `@Guard` (class) or `defineGuard` (function) | — | Custom guard implementations |
39
+
40
+ ### Cross-Cutting Decorators
41
+
42
+ `@ScheduleHandler` and `@Invoke` are cross-cutting — they can be applied to methods on any controller type (HTTP, WebSocket, or Consumer), producing additional manifest entries alongside the primary handler entry.
43
+
27
44
  ## Manifest Structure
28
45
 
29
46
  The output conforms to `handler-manifest.v1.schema.json`:
@@ -51,24 +68,108 @@ The output conforms to `handler-manifest.v1.schema.json`:
51
68
  }
52
69
  }
53
70
  ],
54
- "functionHandlers": [],
71
+ "functionHandlers": [
72
+ {
73
+ "resourceName": "processOrder",
74
+ "exportName": "processOrder",
75
+ "handlerType": "consumer",
76
+ "sourceFile": "/project/src/app.module.ts",
77
+ "annotations": {
78
+ "celerity.handler.consumer": true,
79
+ "celerity.handler.consumer.route": "orders.*"
80
+ },
81
+ "spec": {
82
+ "handlerName": "processOrder",
83
+ "codeLocation": "./src",
84
+ "handler": "app.module.processOrder"
85
+ }
86
+ }
87
+ ],
88
+ "guardHandlers": [
89
+ {
90
+ "resourceName": "rateLimiter_check",
91
+ "guardName": "rateLimiter",
92
+ "guardType": "class",
93
+ "className": "RateLimiter",
94
+ "sourceFile": "/project/src/app.module.ts",
95
+ "annotations": {
96
+ "celerity.handler.guard.custom": "rateLimiter"
97
+ },
98
+ "spec": {
99
+ "handlerName": "RateLimiter-check",
100
+ "codeLocation": "./src",
101
+ "handler": "app.module.RateLimiter.check"
102
+ }
103
+ }
104
+ ],
55
105
  "dependencyGraph": {
56
- "nodes": []
106
+ "nodes": [
107
+ {
108
+ "token": "OrderService",
109
+ "tokenType": "class",
110
+ "providerType": "class",
111
+ "dependencies": ["celerity:datastore:default"]
112
+ }
113
+ ]
57
114
  }
58
115
  }
59
116
  ```
60
117
 
61
118
  ## Annotation Types
62
119
 
120
+ ### HTTP
121
+
63
122
  | Annotation | Source |
64
123
  |---|---|
65
- | `celerity.handler.http` | `@Get`, `@Post`, etc. |
124
+ | `celerity.handler.http` | `@Get`, `@Post`, `@Put`, `@Patch`, `@Delete` |
66
125
  | `celerity.handler.http.method` | HTTP method from decorator |
67
- | `celerity.handler.http.path` | Full path (prefix + route) |
126
+ | `celerity.handler.http.path` | Full path (controller prefix + route) |
127
+
128
+ ### WebSocket
129
+
130
+ | Annotation | Source |
131
+ |---|---|
132
+ | `celerity.handler.websocket` | `@OnConnect`, `@OnDisconnect`, `@OnMessage` |
133
+ | `celerity.handler.websocket.route` | WebSocket route key |
134
+ | `celerity.handler.websocket.eventType` | `connect`, `disconnect`, or `message` |
135
+
136
+ ### Consumer
137
+
138
+ | Annotation | Source |
139
+ |---|---|
140
+ | `celerity.handler.consumer` | `@ConsumerHandler` |
141
+ | `celerity.handler.consumer.sourceId` | Source ID from `@Consumer` controller |
142
+ | `celerity.handler.consumer.route` | Message routing pattern |
143
+
144
+ ### Schedule
145
+
146
+ | Annotation | Source |
147
+ |---|---|
148
+ | `celerity.handler.schedule` | `@ScheduleHandler` |
149
+ | `celerity.handler.schedule.scheduleId` | Schedule identifier |
150
+ | `celerity.handler.schedule.expression` | Cron or rate expression |
151
+
152
+ ### Custom (Invoke)
153
+
154
+ | Annotation | Source |
155
+ |---|---|
156
+ | `celerity.handler.custom` | `@Invoke` |
157
+ | `celerity.handler.custom.name` | Invocation name |
158
+
159
+ ### Guards
160
+
161
+ | Annotation | Source |
162
+ |---|---|
68
163
  | `celerity.handler.guard.protectedBy` | `@ProtectedBy(...)` |
69
- | `celerity.handler.guard.custom` | `@Guard(name)` |
164
+ | `celerity.handler.guard.custom` | `@Guard(name)` or `defineGuard` |
70
165
  | `celerity.handler.public` | `@Public()` |
166
+
167
+ ### Shared
168
+
169
+ | Annotation | Source |
170
+ |---|---|
71
171
  | `celerity.handler.metadata.*` | `@SetMetadata(key, value)`, `@Action(name)` |
172
+ | `celerity.handler.resource.ref` | `@Bucket`, `@Queue`, `@Topic`, etc. |
72
173
 
73
174
  ## Part of the Celerity Framework
74
175
 
@@ -57,10 +57,12 @@ function buildScannedModule(rootModule) {
57
57
  const graph = (0, import_core.buildModuleGraph)(rootModule);
58
58
  const controllerClasses = [];
59
59
  const functionHandlers = [];
60
+ const guardClasses = [];
61
+ const functionGuards = [];
60
62
  const providers = [];
61
63
  const seenTokens = /* @__PURE__ */ new Set();
62
64
  for (const [moduleClass, node] of graph) {
63
- debug("scan: module %s \u2014 %d providers, %d controllers", moduleClass.name, node.providers.length, node.controllers.length);
65
+ debug("scan: module %s \u2014 %d providers, %d controllers, %d guards", moduleClass.name, node.providers.length, node.controllers.length, node.guards.length);
64
66
  for (const provider of node.providers) {
65
67
  const scanned = scanProvider(provider, seenTokens);
66
68
  if (scanned) providers.push(scanned);
@@ -76,11 +78,28 @@ function buildScannedModule(rootModule) {
76
78
  });
77
79
  }
78
80
  }
81
+ for (const guard of node.guards) {
82
+ if (typeof guard === "function") {
83
+ guardClasses.push(guard);
84
+ if (!seenTokens.has(guard)) {
85
+ seenTokens.add(guard);
86
+ providers.push({
87
+ token: guard,
88
+ providerType: "class",
89
+ dependencies: (0, import_core.getClassDependencyTokens)(guard)
90
+ });
91
+ }
92
+ } else {
93
+ functionGuards.push(guard);
94
+ }
95
+ }
79
96
  functionHandlers.push(...node.functionHandlers);
80
97
  }
81
98
  return {
82
99
  controllerClasses,
83
100
  functionHandlers,
101
+ guardClasses,
102
+ functionGuards,
84
103
  providers
85
104
  };
86
105
  }
@@ -165,8 +184,9 @@ __name(deriveCodeLocation, "deriveCodeLocation");
165
184
  function serializeManifest(scanned, sourceFile, options) {
166
185
  const handlers = [];
167
186
  const functionHandlers = [];
187
+ const guardHandlers = [];
168
188
  for (const controllerClass of scanned.controllerClasses) {
169
- const entries = serializeClassHandler(controllerClass, sourceFile, options);
189
+ const entries = serializeClassHandlers(controllerClass, sourceFile, options);
170
190
  handlers.push(...entries);
171
191
  }
172
192
  for (const fnHandler of scanned.functionHandlers) {
@@ -175,40 +195,76 @@ function serializeManifest(scanned, sourceFile, options) {
175
195
  functionHandlers.push(entry);
176
196
  }
177
197
  }
198
+ for (const guardClass of scanned.guardClasses) {
199
+ const entry = serializeClassGuard(guardClass, sourceFile, options);
200
+ if (entry) {
201
+ guardHandlers.push(entry);
202
+ }
203
+ }
204
+ for (const fnGuard of scanned.functionGuards) {
205
+ const entry = serializeFunctionGuard(fnGuard, sourceFile, options);
206
+ if (entry) {
207
+ guardHandlers.push(entry);
208
+ }
209
+ }
178
210
  return {
179
211
  version: "1.0.0",
180
212
  handlers,
181
213
  functionHandlers,
214
+ guardHandlers,
182
215
  dependencyGraph: serializeDependencyGraph(scanned)
183
216
  };
184
217
  }
185
218
  __name(serializeManifest, "serializeManifest");
186
- function extractClassMeta(controllerClass) {
187
- const controllerMeta = Reflect.getOwnMetadata(import_core2.CONTROLLER_METADATA, controllerClass);
188
- if (!controllerMeta) return null;
219
+ function extractControllerMeta(controllerClass) {
220
+ const httpMeta = Reflect.getOwnMetadata(import_core2.CONTROLLER_METADATA, controllerClass);
221
+ if (httpMeta) {
222
+ return {
223
+ controllerType: "http",
224
+ prefix: httpMeta.prefix ?? "",
225
+ ...extractSharedClassMeta(controllerClass)
226
+ };
227
+ }
228
+ const isWebSocket = Reflect.getOwnMetadata(import_core2.WEBSOCKET_CONTROLLER_METADATA, controllerClass);
229
+ if (isWebSocket) {
230
+ return {
231
+ controllerType: "websocket",
232
+ prefix: "",
233
+ ...extractSharedClassMeta(controllerClass)
234
+ };
235
+ }
236
+ const consumerMeta = Reflect.getOwnMetadata(import_core2.CONSUMER_METADATA, controllerClass);
237
+ if (consumerMeta) {
238
+ return {
239
+ controllerType: "consumer",
240
+ prefix: "",
241
+ sourceId: consumerMeta.sourceId,
242
+ ...extractSharedClassMeta(controllerClass)
243
+ };
244
+ }
245
+ return null;
246
+ }
247
+ __name(extractControllerMeta, "extractControllerMeta");
248
+ function extractSharedClassMeta(controllerClass) {
189
249
  return {
190
- prefix: controllerMeta.prefix ?? "",
191
250
  protectedBy: Reflect.getOwnMetadata(import_core2.GUARD_PROTECTEDBY_METADATA, controllerClass) ?? [],
192
251
  customGuardName: Reflect.getOwnMetadata(import_core2.GUARD_CUSTOM_METADATA, controllerClass),
193
- customMetadata: Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, controllerClass) ?? {}
252
+ customMetadata: Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, controllerClass) ?? {},
253
+ resourceRefs: Reflect.getOwnMetadata(import_core2.USE_RESOURCE_METADATA, controllerClass) ?? []
194
254
  };
195
255
  }
196
- __name(extractClassMeta, "extractClassMeta");
197
- function buildMethodAnnotations(classMeta, prototype, methodName, httpMethod, fullPath) {
198
- const annotations = {};
199
- annotations["celerity.handler.http"] = true;
200
- annotations["celerity.handler.http.method"] = httpMethod;
201
- annotations["celerity.handler.http.path"] = fullPath;
256
+ __name(extractSharedClassMeta, "extractSharedClassMeta");
257
+ function appendSharedAnnotations(annotations, meta, prototype, methodName) {
202
258
  const methodProtectedBy = Reflect.getOwnMetadata(import_core2.GUARD_PROTECTEDBY_METADATA, prototype, methodName) ?? [];
203
259
  const allProtectedBy = [
204
- ...classMeta.protectedBy,
260
+ ...meta.protectedBy,
205
261
  ...methodProtectedBy
206
262
  ];
207
263
  if (allProtectedBy.length > 0) {
208
264
  annotations["celerity.handler.guard.protectedBy"] = allProtectedBy;
209
265
  }
210
- if (classMeta.customGuardName) {
211
- annotations["celerity.handler.guard.custom"] = classMeta.customGuardName;
266
+ if (meta.customGuardName) {
267
+ annotations["celerity.handler.guard.custom"] = meta.customGuardName;
212
268
  }
213
269
  const isPublic = Reflect.getOwnMetadata(import_core2.PUBLIC_METADATA, prototype, methodName) === true;
214
270
  if (isPublic) {
@@ -216,57 +272,206 @@ function buildMethodAnnotations(classMeta, prototype, methodName, httpMethod, fu
216
272
  }
217
273
  const methodCustomMetadata = Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, prototype, methodName) ?? {};
218
274
  const customMetadata = {
219
- ...classMeta.customMetadata,
275
+ ...meta.customMetadata,
220
276
  ...methodCustomMetadata
221
277
  };
222
278
  for (const [key, value] of Object.entries(customMetadata)) {
223
279
  if (value === void 0) continue;
224
280
  annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
225
281
  }
282
+ const methodResourceRefs = Reflect.getOwnMetadata(import_core2.USE_RESOURCE_METADATA, prototype, methodName) ?? [];
283
+ const allResourceRefs = [
284
+ .../* @__PURE__ */ new Set([
285
+ ...meta.resourceRefs,
286
+ ...methodResourceRefs
287
+ ])
288
+ ];
289
+ if (allResourceRefs.length > 0) {
290
+ annotations["celerity.handler.resource.ref"] = allResourceRefs;
291
+ }
292
+ }
293
+ __name(appendSharedAnnotations, "appendSharedAnnotations");
294
+ function buildHttpAnnotations(meta, prototype, methodName, httpMethod, fullPath) {
295
+ const annotations = {};
296
+ annotations["celerity.handler.http"] = true;
297
+ annotations["celerity.handler.http.method"] = httpMethod;
298
+ annotations["celerity.handler.http.path"] = fullPath;
299
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
300
+ return annotations;
301
+ }
302
+ __name(buildHttpAnnotations, "buildHttpAnnotations");
303
+ function buildWebSocketAnnotations(meta, prototype, methodName, wsEvent) {
304
+ const annotations = {};
305
+ annotations["celerity.handler.websocket"] = true;
306
+ annotations["celerity.handler.websocket.route"] = wsEvent.route;
307
+ annotations["celerity.handler.websocket.eventType"] = wsEvent.eventType;
308
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
309
+ return annotations;
310
+ }
311
+ __name(buildWebSocketAnnotations, "buildWebSocketAnnotations");
312
+ function buildConsumerAnnotations(meta, prototype, methodName, consumerHandler) {
313
+ const annotations = {};
314
+ annotations["celerity.handler.consumer"] = true;
315
+ if (meta.sourceId) {
316
+ annotations["celerity.handler.consumer.sourceId"] = meta.sourceId;
317
+ }
318
+ if (consumerHandler.route) {
319
+ annotations["celerity.handler.consumer.route"] = consumerHandler.route;
320
+ }
321
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
322
+ return annotations;
323
+ }
324
+ __name(buildConsumerAnnotations, "buildConsumerAnnotations");
325
+ function buildScheduleAnnotations(meta, prototype, methodName, scheduleMeta) {
326
+ const annotations = {};
327
+ annotations["celerity.handler.schedule"] = true;
328
+ if (scheduleMeta.scheduleId) {
329
+ annotations["celerity.handler.schedule.scheduleId"] = scheduleMeta.scheduleId;
330
+ }
331
+ if (scheduleMeta.schedule) {
332
+ annotations["celerity.handler.schedule.expression"] = scheduleMeta.schedule;
333
+ }
334
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
335
+ return annotations;
336
+ }
337
+ __name(buildScheduleAnnotations, "buildScheduleAnnotations");
338
+ function buildCustomAnnotations(meta, prototype, methodName, invokeMeta) {
339
+ const annotations = {};
340
+ annotations["celerity.handler.custom"] = true;
341
+ annotations["celerity.handler.custom.name"] = invokeMeta.name;
342
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
226
343
  return annotations;
227
344
  }
228
- __name(buildMethodAnnotations, "buildMethodAnnotations");
229
- function serializeClassHandler(controllerClass, sourceFile, options) {
230
- const classMeta = extractClassMeta(controllerClass);
231
- if (!classMeta) return [];
345
+ __name(buildCustomAnnotations, "buildCustomAnnotations");
346
+ function serializeClassHandlers(controllerClass, sourceFile, options) {
347
+ const meta = extractControllerMeta(controllerClass);
348
+ if (!meta) return [];
232
349
  const className = controllerClass.name;
233
350
  const prototype = controllerClass.prototype;
234
351
  const methods = Object.getOwnPropertyNames(prototype).filter((n) => n !== "constructor");
235
352
  const entries = [];
236
353
  for (const methodName of methods) {
237
- const httpMethod = Reflect.getOwnMetadata(import_core2.HTTP_METHOD_METADATA, prototype, methodName);
238
- if (!httpMethod) continue;
239
- const routePath = Reflect.getOwnMetadata(import_core2.ROUTE_PATH_METADATA, prototype, methodName) ?? "/";
240
- const fullPath = (0, import_common.joinHandlerPath)(classMeta.prefix, routePath);
241
- const annotations = buildMethodAnnotations(classMeta, prototype, methodName, httpMethod, fullPath);
242
- entries.push({
243
- resourceName: deriveClassResourceName(className, methodName),
244
- className,
245
- methodName,
246
- sourceFile,
247
- handlerType: "http",
248
- annotations,
249
- spec: {
250
- handlerName: deriveClassHandlerName(className, methodName),
251
- codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
252
- handler: deriveClassHandlerFunction(sourceFile, className, methodName)
253
- }
254
- });
354
+ const typeEntry = serializeControllerTypeMethod(meta, className, prototype, methodName, sourceFile, options);
355
+ if (typeEntry) entries.push(typeEntry);
356
+ const scheduleMeta = Reflect.getOwnMetadata(import_core2.SCHEDULE_HANDLER_METADATA, prototype, methodName);
357
+ if (scheduleMeta) {
358
+ entries.push({
359
+ resourceName: deriveClassResourceName(className, methodName),
360
+ className,
361
+ methodName,
362
+ sourceFile,
363
+ handlerType: "schedule",
364
+ annotations: buildScheduleAnnotations(meta, prototype, methodName, scheduleMeta),
365
+ spec: {
366
+ handlerName: deriveClassHandlerName(className, methodName),
367
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
368
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
369
+ }
370
+ });
371
+ }
372
+ const invokeMeta = Reflect.getOwnMetadata(import_core2.INVOKE_METADATA, prototype, methodName);
373
+ if (invokeMeta) {
374
+ entries.push({
375
+ resourceName: deriveClassResourceName(className, methodName),
376
+ className,
377
+ methodName,
378
+ sourceFile,
379
+ handlerType: "custom",
380
+ annotations: buildCustomAnnotations(meta, prototype, methodName, invokeMeta),
381
+ spec: {
382
+ handlerName: deriveClassHandlerName(className, methodName),
383
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
384
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
385
+ }
386
+ });
387
+ }
255
388
  }
256
389
  return entries;
257
390
  }
258
- __name(serializeClassHandler, "serializeClassHandler");
391
+ __name(serializeClassHandlers, "serializeClassHandlers");
392
+ function serializeControllerTypeMethod(meta, className, prototype, methodName, sourceFile, options) {
393
+ switch (meta.controllerType) {
394
+ case "http":
395
+ return serializeHttpMethod(meta, className, prototype, methodName, sourceFile, options);
396
+ case "websocket":
397
+ return serializeWebSocketMethod(meta, className, prototype, methodName, sourceFile, options);
398
+ case "consumer":
399
+ return serializeConsumerMethod(meta, className, prototype, methodName, sourceFile, options);
400
+ default:
401
+ return null;
402
+ }
403
+ }
404
+ __name(serializeControllerTypeMethod, "serializeControllerTypeMethod");
405
+ function serializeHttpMethod(meta, className, prototype, methodName, sourceFile, options) {
406
+ const httpMethod = Reflect.getOwnMetadata(import_core2.HTTP_METHOD_METADATA, prototype, methodName);
407
+ if (!httpMethod) return null;
408
+ const routePath = Reflect.getOwnMetadata(import_core2.ROUTE_PATH_METADATA, prototype, methodName) ?? "/";
409
+ const fullPath = (0, import_common.joinHandlerPath)(meta.prefix, routePath);
410
+ return {
411
+ resourceName: deriveClassResourceName(className, methodName),
412
+ className,
413
+ methodName,
414
+ sourceFile,
415
+ handlerType: "http",
416
+ annotations: buildHttpAnnotations(meta, prototype, methodName, httpMethod, fullPath),
417
+ spec: {
418
+ handlerName: deriveClassHandlerName(className, methodName),
419
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
420
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
421
+ }
422
+ };
423
+ }
424
+ __name(serializeHttpMethod, "serializeHttpMethod");
425
+ function serializeWebSocketMethod(meta, className, prototype, methodName, sourceFile, options) {
426
+ const wsEvent = Reflect.getOwnMetadata(import_core2.WEBSOCKET_EVENT_METADATA, prototype, methodName);
427
+ if (!wsEvent) return null;
428
+ return {
429
+ resourceName: deriveClassResourceName(className, methodName),
430
+ className,
431
+ methodName,
432
+ sourceFile,
433
+ handlerType: "websocket",
434
+ annotations: buildWebSocketAnnotations(meta, prototype, methodName, wsEvent),
435
+ spec: {
436
+ handlerName: deriveClassHandlerName(className, methodName),
437
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
438
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
439
+ }
440
+ };
441
+ }
442
+ __name(serializeWebSocketMethod, "serializeWebSocketMethod");
443
+ function serializeConsumerMethod(meta, className, prototype, methodName, sourceFile, options) {
444
+ const consumerHandler = Reflect.getOwnMetadata(import_core2.CONSUMER_HANDLER_METADATA, prototype, methodName);
445
+ if (!consumerHandler) return null;
446
+ return {
447
+ resourceName: deriveClassResourceName(className, methodName),
448
+ className,
449
+ methodName,
450
+ sourceFile,
451
+ handlerType: "consumer",
452
+ annotations: buildConsumerAnnotations(meta, prototype, methodName, consumerHandler),
453
+ spec: {
454
+ handlerName: deriveClassHandlerName(className, methodName),
455
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
456
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
457
+ }
458
+ };
459
+ }
460
+ __name(serializeConsumerMethod, "serializeConsumerMethod");
259
461
  function serializeFunctionHandler(definition, sourceFile, options) {
462
+ const supported = [
463
+ "http",
464
+ "websocket",
465
+ "consumer",
466
+ "schedule",
467
+ "custom"
468
+ ];
469
+ if (!supported.includes(definition.type)) return null;
260
470
  const exportName = definition.metadata.handlerName ?? "handler";
261
471
  const customMetadata = definition.metadata.customMetadata ?? {};
472
+ const handlerType = definition.type;
262
473
  const annotations = {};
263
- const path = definition.metadata.path;
264
- const method = definition.metadata.method;
265
- if (path !== void 0 && method !== void 0) {
266
- annotations["celerity.handler.http"] = true;
267
- annotations["celerity.handler.http.method"] = method;
268
- annotations["celerity.handler.http.path"] = path;
269
- }
474
+ buildFunctionTypeAnnotations(annotations, definition);
270
475
  for (const [key, value] of Object.entries(customMetadata)) {
271
476
  if (value === void 0) continue;
272
477
  annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
@@ -275,6 +480,7 @@ function serializeFunctionHandler(definition, sourceFile, options) {
275
480
  resourceName: deriveFunctionResourceName(exportName),
276
481
  exportName,
277
482
  sourceFile,
483
+ handlerType,
278
484
  ...Object.keys(annotations).length > 0 ? {
279
485
  annotations
280
486
  } : {},
@@ -286,6 +492,122 @@ function serializeFunctionHandler(definition, sourceFile, options) {
286
492
  };
287
493
  }
288
494
  __name(serializeFunctionHandler, "serializeFunctionHandler");
495
+ function buildFunctionTypeAnnotations(annotations, definition) {
496
+ const meta = definition.metadata;
497
+ switch (definition.type) {
498
+ case "http": {
499
+ const path = meta.path;
500
+ const method = meta.method;
501
+ if (path !== void 0 && method !== void 0) {
502
+ annotations["celerity.handler.http"] = true;
503
+ annotations["celerity.handler.http.method"] = method;
504
+ annotations["celerity.handler.http.path"] = path;
505
+ }
506
+ break;
507
+ }
508
+ case "websocket": {
509
+ annotations["celerity.handler.websocket"] = true;
510
+ const route = meta.route;
511
+ if (route) {
512
+ annotations["celerity.handler.websocket.route"] = route;
513
+ }
514
+ break;
515
+ }
516
+ case "consumer": {
517
+ annotations["celerity.handler.consumer"] = true;
518
+ const route = meta.route;
519
+ if (route) {
520
+ annotations["celerity.handler.consumer.route"] = route;
521
+ }
522
+ break;
523
+ }
524
+ case "schedule": {
525
+ annotations["celerity.handler.schedule"] = true;
526
+ const scheduleId = meta.scheduleId;
527
+ if (scheduleId) {
528
+ annotations["celerity.handler.schedule.scheduleId"] = scheduleId;
529
+ }
530
+ const schedule = meta.schedule;
531
+ if (schedule) {
532
+ annotations["celerity.handler.schedule.expression"] = schedule;
533
+ }
534
+ break;
535
+ }
536
+ case "custom": {
537
+ annotations["celerity.handler.custom"] = true;
538
+ const name = meta.name;
539
+ if (name) {
540
+ annotations["celerity.handler.custom.name"] = name;
541
+ }
542
+ break;
543
+ }
544
+ }
545
+ }
546
+ __name(buildFunctionTypeAnnotations, "buildFunctionTypeAnnotations");
547
+ function extractGuardMeta(guardClass) {
548
+ const guardName = Reflect.getOwnMetadata(import_core2.GUARD_CUSTOM_METADATA, guardClass);
549
+ if (!guardName) return null;
550
+ return {
551
+ guardName,
552
+ customMetadata: Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, guardClass) ?? {}
553
+ };
554
+ }
555
+ __name(extractGuardMeta, "extractGuardMeta");
556
+ function serializeClassGuard(guardClass, sourceFile, options) {
557
+ const meta = extractGuardMeta(guardClass);
558
+ if (!meta) return null;
559
+ const className = guardClass.name;
560
+ const methodName = "check";
561
+ const annotations = {
562
+ "celerity.handler.guard.custom": meta.guardName
563
+ };
564
+ for (const [key, value] of Object.entries(meta.customMetadata)) {
565
+ if (value === void 0) continue;
566
+ annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
567
+ }
568
+ return {
569
+ resourceName: deriveClassResourceName(className, methodName),
570
+ guardName: meta.guardName,
571
+ sourceFile,
572
+ guardType: "class",
573
+ className,
574
+ annotations,
575
+ spec: {
576
+ handlerName: deriveClassHandlerName(className, methodName),
577
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
578
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
579
+ }
580
+ };
581
+ }
582
+ __name(serializeClassGuard, "serializeClassGuard");
583
+ function serializeFunctionGuard(definition, sourceFile, options) {
584
+ const guardName = definition.name;
585
+ if (!guardName) return null;
586
+ const meta = definition.metadata ?? {};
587
+ const customMetadata = meta.customMetadata ?? {};
588
+ const annotations = {
589
+ "celerity.handler.guard.custom": guardName
590
+ };
591
+ for (const [key, value] of Object.entries(customMetadata)) {
592
+ if (value === void 0) continue;
593
+ annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
594
+ }
595
+ const exportName = guardName;
596
+ return {
597
+ resourceName: deriveFunctionResourceName(exportName),
598
+ guardName,
599
+ sourceFile,
600
+ guardType: "function",
601
+ exportName,
602
+ annotations,
603
+ spec: {
604
+ handlerName: exportName,
605
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
606
+ handler: deriveFunctionHandlerFunction(sourceFile, exportName)
607
+ }
608
+ };
609
+ }
610
+ __name(serializeFunctionGuard, "serializeFunctionGuard");
289
611
  function serializeAnnotationValue(value) {
290
612
  if (typeof value === "boolean") return value;
291
613
  if (typeof value === "string") return value;