@celerity-sdk/cli 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/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.source` | Blueprint resource name 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.source` | Blueprint resource name from `@ScheduleHandler` |
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
 
@@ -31,6 +31,7 @@ var import_debug2 = __toESM(require("debug"), 1);
31
31
  // src/extract/metadata-app.ts
32
32
  var import_reflect_metadata = require("reflect-metadata");
33
33
  var import_debug = __toESM(require("debug"), 1);
34
+ var import_common = require("@celerity-sdk/common");
34
35
  var import_core = require("@celerity-sdk/core");
35
36
  var debug = (0, import_debug.default)("celerity:cli");
36
37
  function scanProvider(provider, seenTokens) {
@@ -57,10 +58,12 @@ function buildScannedModule(rootModule) {
57
58
  const graph = (0, import_core.buildModuleGraph)(rootModule);
58
59
  const controllerClasses = [];
59
60
  const functionHandlers = [];
61
+ const guardClasses = [];
62
+ const functionGuards = [];
60
63
  const providers = [];
61
64
  const seenTokens = /* @__PURE__ */ new Set();
62
65
  for (const [moduleClass, node] of graph) {
63
- debug("scan: module %s \u2014 %d providers, %d controllers", moduleClass.name, node.providers.length, node.controllers.length);
66
+ debug("scan: module %s \u2014 %d providers, %d controllers, %d guards", moduleClass.name, node.providers.length, node.controllers.length, node.guards.length);
64
67
  for (const provider of node.providers) {
65
68
  const scanned = scanProvider(provider, seenTokens);
66
69
  if (scanned) providers.push(scanned);
@@ -76,11 +79,28 @@ function buildScannedModule(rootModule) {
76
79
  });
77
80
  }
78
81
  }
82
+ for (const guard of node.guards) {
83
+ if (typeof guard === "function") {
84
+ guardClasses.push(guard);
85
+ if (!seenTokens.has(guard)) {
86
+ seenTokens.add(guard);
87
+ providers.push({
88
+ token: guard,
89
+ providerType: "class",
90
+ dependencies: (0, import_core.getClassDependencyTokens)(guard)
91
+ });
92
+ }
93
+ } else {
94
+ functionGuards.push(guard);
95
+ }
96
+ }
79
97
  functionHandlers.push(...node.functionHandlers);
80
98
  }
81
99
  return {
82
100
  controllerClasses,
83
101
  functionHandlers,
102
+ guardClasses,
103
+ functionGuards,
84
104
  providers
85
105
  };
86
106
  }
@@ -100,7 +120,7 @@ function validateScannedDependencies(scanned) {
100
120
  }
101
121
  } else if (typeof dep === "function") {
102
122
  walk(dep, (0, import_core.getClassDependencyTokens)(dep));
103
- } else {
123
+ } else if (!(0, import_common.isResourceLayerToken)(dep)) {
104
124
  diagnostics.push({
105
125
  consumer: serializeToken(token),
106
126
  dependency: serializeToken(dep)
@@ -127,7 +147,7 @@ var import_reflect_metadata2 = require("reflect-metadata");
127
147
  var import_core2 = require("@celerity-sdk/core");
128
148
 
129
149
  // src/extract/path-utils.ts
130
- var import_common = require("@celerity-sdk/common");
150
+ var import_common2 = require("@celerity-sdk/common");
131
151
 
132
152
  // src/extract/identity.ts
133
153
  var import_node_path = require("path");
@@ -165,8 +185,9 @@ __name(deriveCodeLocation, "deriveCodeLocation");
165
185
  function serializeManifest(scanned, sourceFile, options) {
166
186
  const handlers = [];
167
187
  const functionHandlers = [];
188
+ const guardHandlers = [];
168
189
  for (const controllerClass of scanned.controllerClasses) {
169
- const entries = serializeClassHandler(controllerClass, sourceFile, options);
190
+ const entries = serializeClassHandlers(controllerClass, sourceFile, options);
170
191
  handlers.push(...entries);
171
192
  }
172
193
  for (const fnHandler of scanned.functionHandlers) {
@@ -175,40 +196,76 @@ function serializeManifest(scanned, sourceFile, options) {
175
196
  functionHandlers.push(entry);
176
197
  }
177
198
  }
199
+ for (const guardClass of scanned.guardClasses) {
200
+ const entry = serializeClassGuard(guardClass, sourceFile, options);
201
+ if (entry) {
202
+ guardHandlers.push(entry);
203
+ }
204
+ }
205
+ for (const fnGuard of scanned.functionGuards) {
206
+ const entry = serializeFunctionGuard(fnGuard, sourceFile, options);
207
+ if (entry) {
208
+ guardHandlers.push(entry);
209
+ }
210
+ }
178
211
  return {
179
212
  version: "1.0.0",
180
213
  handlers,
181
214
  functionHandlers,
215
+ guardHandlers,
182
216
  dependencyGraph: serializeDependencyGraph(scanned)
183
217
  };
184
218
  }
185
219
  __name(serializeManifest, "serializeManifest");
186
- function extractClassMeta(controllerClass) {
187
- const controllerMeta = Reflect.getOwnMetadata(import_core2.CONTROLLER_METADATA, controllerClass);
188
- if (!controllerMeta) return null;
220
+ function extractControllerMeta(controllerClass) {
221
+ const httpMeta = Reflect.getOwnMetadata(import_core2.CONTROLLER_METADATA, controllerClass);
222
+ if (httpMeta) {
223
+ return {
224
+ controllerType: "http",
225
+ prefix: httpMeta.prefix ?? "",
226
+ ...extractSharedClassMeta(controllerClass)
227
+ };
228
+ }
229
+ const isWebSocket = Reflect.getOwnMetadata(import_core2.WEBSOCKET_CONTROLLER_METADATA, controllerClass);
230
+ if (isWebSocket) {
231
+ return {
232
+ controllerType: "websocket",
233
+ prefix: "",
234
+ ...extractSharedClassMeta(controllerClass)
235
+ };
236
+ }
237
+ const consumerMeta = Reflect.getOwnMetadata(import_core2.CONSUMER_METADATA, controllerClass);
238
+ if (consumerMeta) {
239
+ return {
240
+ controllerType: "consumer",
241
+ prefix: "",
242
+ source: consumerMeta.source,
243
+ ...extractSharedClassMeta(controllerClass)
244
+ };
245
+ }
246
+ return null;
247
+ }
248
+ __name(extractControllerMeta, "extractControllerMeta");
249
+ function extractSharedClassMeta(controllerClass) {
189
250
  return {
190
- prefix: controllerMeta.prefix ?? "",
191
251
  protectedBy: Reflect.getOwnMetadata(import_core2.GUARD_PROTECTEDBY_METADATA, controllerClass) ?? [],
192
252
  customGuardName: Reflect.getOwnMetadata(import_core2.GUARD_CUSTOM_METADATA, controllerClass),
193
- customMetadata: Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, controllerClass) ?? {}
253
+ customMetadata: Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, controllerClass) ?? {},
254
+ resourceRefs: Reflect.getOwnMetadata(import_core2.USE_RESOURCE_METADATA, controllerClass) ?? []
194
255
  };
195
256
  }
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;
257
+ __name(extractSharedClassMeta, "extractSharedClassMeta");
258
+ function appendSharedAnnotations(annotations, meta, prototype, methodName) {
202
259
  const methodProtectedBy = Reflect.getOwnMetadata(import_core2.GUARD_PROTECTEDBY_METADATA, prototype, methodName) ?? [];
203
260
  const allProtectedBy = [
204
- ...classMeta.protectedBy,
261
+ ...meta.protectedBy,
205
262
  ...methodProtectedBy
206
263
  ];
207
264
  if (allProtectedBy.length > 0) {
208
265
  annotations["celerity.handler.guard.protectedBy"] = allProtectedBy;
209
266
  }
210
- if (classMeta.customGuardName) {
211
- annotations["celerity.handler.guard.custom"] = classMeta.customGuardName;
267
+ if (meta.customGuardName) {
268
+ annotations["celerity.handler.guard.custom"] = meta.customGuardName;
212
269
  }
213
270
  const isPublic = Reflect.getOwnMetadata(import_core2.PUBLIC_METADATA, prototype, methodName) === true;
214
271
  if (isPublic) {
@@ -216,57 +273,206 @@ function buildMethodAnnotations(classMeta, prototype, methodName, httpMethod, fu
216
273
  }
217
274
  const methodCustomMetadata = Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, prototype, methodName) ?? {};
218
275
  const customMetadata = {
219
- ...classMeta.customMetadata,
276
+ ...meta.customMetadata,
220
277
  ...methodCustomMetadata
221
278
  };
222
279
  for (const [key, value] of Object.entries(customMetadata)) {
223
280
  if (value === void 0) continue;
224
281
  annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
225
282
  }
283
+ const methodResourceRefs = Reflect.getOwnMetadata(import_core2.USE_RESOURCE_METADATA, prototype, methodName) ?? [];
284
+ const allResourceRefs = [
285
+ .../* @__PURE__ */ new Set([
286
+ ...meta.resourceRefs,
287
+ ...methodResourceRefs
288
+ ])
289
+ ];
290
+ if (allResourceRefs.length > 0) {
291
+ annotations["celerity.handler.resource.ref"] = allResourceRefs;
292
+ }
293
+ }
294
+ __name(appendSharedAnnotations, "appendSharedAnnotations");
295
+ function buildHttpAnnotations(meta, prototype, methodName, httpMethod, fullPath) {
296
+ const annotations = {};
297
+ annotations["celerity.handler.http"] = true;
298
+ annotations["celerity.handler.http.method"] = httpMethod;
299
+ annotations["celerity.handler.http.path"] = fullPath;
300
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
301
+ return annotations;
302
+ }
303
+ __name(buildHttpAnnotations, "buildHttpAnnotations");
304
+ function buildWebSocketAnnotations(meta, prototype, methodName, wsEvent) {
305
+ const annotations = {};
306
+ annotations["celerity.handler.websocket"] = true;
307
+ annotations["celerity.handler.websocket.route"] = wsEvent.route;
308
+ annotations["celerity.handler.websocket.eventType"] = wsEvent.eventType;
309
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
310
+ return annotations;
311
+ }
312
+ __name(buildWebSocketAnnotations, "buildWebSocketAnnotations");
313
+ function buildConsumerAnnotations(meta, prototype, methodName, consumerHandler) {
314
+ const annotations = {};
315
+ annotations["celerity.handler.consumer"] = true;
316
+ if (meta.source) {
317
+ annotations["celerity.handler.consumer.source"] = meta.source;
318
+ }
319
+ if (consumerHandler.route) {
320
+ annotations["celerity.handler.consumer.route"] = consumerHandler.route;
321
+ }
322
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
323
+ return annotations;
324
+ }
325
+ __name(buildConsumerAnnotations, "buildConsumerAnnotations");
326
+ function buildScheduleAnnotations(meta, prototype, methodName, scheduleMeta) {
327
+ const annotations = {};
328
+ annotations["celerity.handler.schedule"] = true;
329
+ if (scheduleMeta.source) {
330
+ annotations["celerity.handler.schedule.source"] = scheduleMeta.source;
331
+ }
332
+ if (scheduleMeta.schedule) {
333
+ annotations["celerity.handler.schedule.expression"] = scheduleMeta.schedule;
334
+ }
335
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
226
336
  return annotations;
227
337
  }
228
- __name(buildMethodAnnotations, "buildMethodAnnotations");
229
- function serializeClassHandler(controllerClass, sourceFile, options) {
230
- const classMeta = extractClassMeta(controllerClass);
231
- if (!classMeta) return [];
338
+ __name(buildScheduleAnnotations, "buildScheduleAnnotations");
339
+ function buildCustomAnnotations(meta, prototype, methodName, invokeMeta) {
340
+ const annotations = {};
341
+ annotations["celerity.handler.custom"] = true;
342
+ annotations["celerity.handler.custom.name"] = invokeMeta.name;
343
+ appendSharedAnnotations(annotations, meta, prototype, methodName);
344
+ return annotations;
345
+ }
346
+ __name(buildCustomAnnotations, "buildCustomAnnotations");
347
+ function serializeClassHandlers(controllerClass, sourceFile, options) {
348
+ const meta = extractControllerMeta(controllerClass);
349
+ if (!meta) return [];
232
350
  const className = controllerClass.name;
233
351
  const prototype = controllerClass.prototype;
234
352
  const methods = Object.getOwnPropertyNames(prototype).filter((n) => n !== "constructor");
235
353
  const entries = [];
236
354
  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
- });
355
+ const typeEntry = serializeControllerTypeMethod(meta, className, prototype, methodName, sourceFile, options);
356
+ if (typeEntry) entries.push(typeEntry);
357
+ const scheduleMeta = Reflect.getOwnMetadata(import_core2.SCHEDULE_HANDLER_METADATA, prototype, methodName);
358
+ if (scheduleMeta) {
359
+ entries.push({
360
+ resourceName: deriveClassResourceName(className, methodName),
361
+ className,
362
+ methodName,
363
+ sourceFile,
364
+ handlerType: "schedule",
365
+ annotations: buildScheduleAnnotations(meta, prototype, methodName, scheduleMeta),
366
+ spec: {
367
+ handlerName: deriveClassHandlerName(className, methodName),
368
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
369
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
370
+ }
371
+ });
372
+ }
373
+ const invokeMeta = Reflect.getOwnMetadata(import_core2.INVOKE_METADATA, prototype, methodName);
374
+ if (invokeMeta) {
375
+ entries.push({
376
+ resourceName: deriveClassResourceName(className, methodName),
377
+ className,
378
+ methodName,
379
+ sourceFile,
380
+ handlerType: "custom",
381
+ annotations: buildCustomAnnotations(meta, prototype, methodName, invokeMeta),
382
+ spec: {
383
+ handlerName: deriveClassHandlerName(className, methodName),
384
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
385
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
386
+ }
387
+ });
388
+ }
255
389
  }
256
390
  return entries;
257
391
  }
258
- __name(serializeClassHandler, "serializeClassHandler");
392
+ __name(serializeClassHandlers, "serializeClassHandlers");
393
+ function serializeControllerTypeMethod(meta, className, prototype, methodName, sourceFile, options) {
394
+ switch (meta.controllerType) {
395
+ case "http":
396
+ return serializeHttpMethod(meta, className, prototype, methodName, sourceFile, options);
397
+ case "websocket":
398
+ return serializeWebSocketMethod(meta, className, prototype, methodName, sourceFile, options);
399
+ case "consumer":
400
+ return serializeConsumerMethod(meta, className, prototype, methodName, sourceFile, options);
401
+ default:
402
+ return null;
403
+ }
404
+ }
405
+ __name(serializeControllerTypeMethod, "serializeControllerTypeMethod");
406
+ function serializeHttpMethod(meta, className, prototype, methodName, sourceFile, options) {
407
+ const httpMethod = Reflect.getOwnMetadata(import_core2.HTTP_METHOD_METADATA, prototype, methodName);
408
+ if (!httpMethod) return null;
409
+ const routePath = Reflect.getOwnMetadata(import_core2.ROUTE_PATH_METADATA, prototype, methodName) ?? "/";
410
+ const fullPath = (0, import_common2.joinHandlerPath)(meta.prefix, routePath);
411
+ return {
412
+ resourceName: deriveClassResourceName(className, methodName),
413
+ className,
414
+ methodName,
415
+ sourceFile,
416
+ handlerType: "http",
417
+ annotations: buildHttpAnnotations(meta, prototype, methodName, httpMethod, fullPath),
418
+ spec: {
419
+ handlerName: deriveClassHandlerName(className, methodName),
420
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
421
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
422
+ }
423
+ };
424
+ }
425
+ __name(serializeHttpMethod, "serializeHttpMethod");
426
+ function serializeWebSocketMethod(meta, className, prototype, methodName, sourceFile, options) {
427
+ const wsEvent = Reflect.getOwnMetadata(import_core2.WEBSOCKET_EVENT_METADATA, prototype, methodName);
428
+ if (!wsEvent) return null;
429
+ return {
430
+ resourceName: deriveClassResourceName(className, methodName),
431
+ className,
432
+ methodName,
433
+ sourceFile,
434
+ handlerType: "websocket",
435
+ annotations: buildWebSocketAnnotations(meta, prototype, methodName, wsEvent),
436
+ spec: {
437
+ handlerName: deriveClassHandlerName(className, methodName),
438
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
439
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
440
+ }
441
+ };
442
+ }
443
+ __name(serializeWebSocketMethod, "serializeWebSocketMethod");
444
+ function serializeConsumerMethod(meta, className, prototype, methodName, sourceFile, options) {
445
+ const consumerHandler = Reflect.getOwnMetadata(import_core2.CONSUMER_HANDLER_METADATA, prototype, methodName);
446
+ if (!consumerHandler) return null;
447
+ return {
448
+ resourceName: deriveClassResourceName(className, methodName),
449
+ className,
450
+ methodName,
451
+ sourceFile,
452
+ handlerType: "consumer",
453
+ annotations: buildConsumerAnnotations(meta, prototype, methodName, consumerHandler),
454
+ spec: {
455
+ handlerName: deriveClassHandlerName(className, methodName),
456
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
457
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
458
+ }
459
+ };
460
+ }
461
+ __name(serializeConsumerMethod, "serializeConsumerMethod");
259
462
  function serializeFunctionHandler(definition, sourceFile, options) {
463
+ const supported = [
464
+ "http",
465
+ "websocket",
466
+ "consumer",
467
+ "schedule",
468
+ "custom"
469
+ ];
470
+ if (!supported.includes(definition.type)) return null;
260
471
  const exportName = definition.metadata.handlerName ?? "handler";
261
472
  const customMetadata = definition.metadata.customMetadata ?? {};
473
+ const handlerType = definition.type;
262
474
  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
- }
475
+ buildFunctionTypeAnnotations(annotations, definition);
270
476
  for (const [key, value] of Object.entries(customMetadata)) {
271
477
  if (value === void 0) continue;
272
478
  annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
@@ -275,6 +481,7 @@ function serializeFunctionHandler(definition, sourceFile, options) {
275
481
  resourceName: deriveFunctionResourceName(exportName),
276
482
  exportName,
277
483
  sourceFile,
484
+ handlerType,
278
485
  ...Object.keys(annotations).length > 0 ? {
279
486
  annotations
280
487
  } : {},
@@ -286,6 +493,122 @@ function serializeFunctionHandler(definition, sourceFile, options) {
286
493
  };
287
494
  }
288
495
  __name(serializeFunctionHandler, "serializeFunctionHandler");
496
+ function buildFunctionTypeAnnotations(annotations, definition) {
497
+ const meta = definition.metadata;
498
+ switch (definition.type) {
499
+ case "http": {
500
+ const path = meta.path;
501
+ const method = meta.method;
502
+ if (path !== void 0 && method !== void 0) {
503
+ annotations["celerity.handler.http"] = true;
504
+ annotations["celerity.handler.http.method"] = method;
505
+ annotations["celerity.handler.http.path"] = path;
506
+ }
507
+ break;
508
+ }
509
+ case "websocket": {
510
+ annotations["celerity.handler.websocket"] = true;
511
+ const route = meta.route;
512
+ if (route) {
513
+ annotations["celerity.handler.websocket.route"] = route;
514
+ }
515
+ break;
516
+ }
517
+ case "consumer": {
518
+ annotations["celerity.handler.consumer"] = true;
519
+ const route = meta.route;
520
+ if (route) {
521
+ annotations["celerity.handler.consumer.route"] = route;
522
+ }
523
+ break;
524
+ }
525
+ case "schedule": {
526
+ annotations["celerity.handler.schedule"] = true;
527
+ const source = meta.source;
528
+ if (source) {
529
+ annotations["celerity.handler.schedule.source"] = source;
530
+ }
531
+ const schedule = meta.schedule;
532
+ if (schedule) {
533
+ annotations["celerity.handler.schedule.expression"] = schedule;
534
+ }
535
+ break;
536
+ }
537
+ case "custom": {
538
+ annotations["celerity.handler.custom"] = true;
539
+ const name = meta.name;
540
+ if (name) {
541
+ annotations["celerity.handler.custom.name"] = name;
542
+ }
543
+ break;
544
+ }
545
+ }
546
+ }
547
+ __name(buildFunctionTypeAnnotations, "buildFunctionTypeAnnotations");
548
+ function extractGuardMeta(guardClass) {
549
+ const guardName = Reflect.getOwnMetadata(import_core2.GUARD_CUSTOM_METADATA, guardClass);
550
+ if (!guardName) return null;
551
+ return {
552
+ guardName,
553
+ customMetadata: Reflect.getOwnMetadata(import_core2.CUSTOM_METADATA, guardClass) ?? {}
554
+ };
555
+ }
556
+ __name(extractGuardMeta, "extractGuardMeta");
557
+ function serializeClassGuard(guardClass, sourceFile, options) {
558
+ const meta = extractGuardMeta(guardClass);
559
+ if (!meta) return null;
560
+ const className = guardClass.name;
561
+ const methodName = "check";
562
+ const annotations = {
563
+ "celerity.handler.guard.custom": meta.guardName
564
+ };
565
+ for (const [key, value] of Object.entries(meta.customMetadata)) {
566
+ if (value === void 0) continue;
567
+ annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
568
+ }
569
+ return {
570
+ resourceName: deriveClassResourceName(className, methodName),
571
+ guardName: meta.guardName,
572
+ sourceFile,
573
+ guardType: "class",
574
+ className,
575
+ annotations,
576
+ spec: {
577
+ handlerName: deriveClassHandlerName(className, methodName),
578
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
579
+ handler: deriveClassHandlerFunction(sourceFile, className, methodName)
580
+ }
581
+ };
582
+ }
583
+ __name(serializeClassGuard, "serializeClassGuard");
584
+ function serializeFunctionGuard(definition, sourceFile, options) {
585
+ const guardName = definition.name;
586
+ if (!guardName) return null;
587
+ const meta = definition.metadata ?? {};
588
+ const customMetadata = meta.customMetadata ?? {};
589
+ const annotations = {
590
+ "celerity.handler.guard.custom": guardName
591
+ };
592
+ for (const [key, value] of Object.entries(customMetadata)) {
593
+ if (value === void 0) continue;
594
+ annotations[`celerity.handler.metadata.${key}`] = serializeAnnotationValue(value);
595
+ }
596
+ const exportName = guardName;
597
+ return {
598
+ resourceName: deriveFunctionResourceName(exportName),
599
+ guardName,
600
+ sourceFile,
601
+ guardType: "function",
602
+ exportName,
603
+ annotations,
604
+ spec: {
605
+ handlerName: exportName,
606
+ codeLocation: deriveCodeLocation(sourceFile, options.projectRoot),
607
+ handler: deriveFunctionHandlerFunction(sourceFile, exportName)
608
+ }
609
+ };
610
+ }
611
+ __name(serializeFunctionGuard, "serializeFunctionGuard");
289
612
  function serializeAnnotationValue(value) {
290
613
  if (typeof value === "boolean") return value;
291
614
  if (typeof value === "string") return value;