@celerity-sdk/core 0.2.0 → 0.3.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
@@ -153,6 +153,7 @@ declare const APP_CONFIG: unique symbol;
153
153
  declare const RUNTIME_APP: unique symbol;
154
154
 
155
155
  type ResolvedHandler = {
156
+ id?: string;
156
157
  path?: string;
157
158
  method?: string;
158
159
  protectedBy: string[];
@@ -200,6 +201,7 @@ declare function registerModuleGraph(graph: ModuleGraph, container: Container):
200
201
  declare class HandlerRegistry {
201
202
  private handlers;
202
203
  getHandler(path: string, method: string): ResolvedHandler | undefined;
204
+ getHandlerById(id: string): ResolvedHandler | undefined;
203
205
  getAllHandlers(): ResolvedHandler[];
204
206
  populateFromGraph(graph: ModuleGraph, container: Container): Promise<void>;
205
207
  scanModule(moduleClass: Type, container: Container): Promise<void>;
@@ -380,6 +382,25 @@ declare class GatewayTimeoutException extends HttpException {
380
382
  constructor(message?: string, details?: unknown);
381
383
  }
382
384
 
385
+ /**
386
+ * Resolve a handler ID as a module reference by dynamically importing
387
+ * the module and matching the exported function against the registry.
388
+ *
389
+ * Resolution strategy:
390
+ * 1. If the ID contains a dot, try splitting at the last dot into
391
+ * `moduleName.exportName` (named export).
392
+ * 2. Fallback: treat the full ID as a module name with a default export.
393
+ * This handles no-dot refs (e.g. "myModule") and dotted module names
394
+ * (e.g. "app.module" from app.module.js) where the named export split failed.
395
+ *
396
+ * Supported formats:
397
+ * - `"handlers.hello"` — named export `hello` from module `handlers`
398
+ * - `"handlers"` — default export from module `handlers`
399
+ * - `"app.module"` — dotted module name: tries named export split first,
400
+ * falls back to default export from module `app.module`
401
+ */
402
+ declare function resolveHandlerByModuleRef(handlerId: string, registry: HandlerRegistry, baseDir: string): Promise<ResolvedHandler | null>;
403
+
383
404
  declare const CONTROLLER_METADATA: unique symbol;
384
405
  declare const HTTP_METHOD_METADATA: unique symbol;
385
406
  declare const ROUTE_PATH_METADATA: unique symbol;
@@ -408,11 +429,25 @@ declare function mapRuntimeRequest(request: Request): HttpRequest;
408
429
  /** Convert SDK HttpResponse → NAPI runtime Response. */
409
430
  declare function mapToRuntimeResponse(response: HttpResponse): Response;
410
431
 
432
+ type RuntimeCallback = (err: Error | null, request: Request) => Promise<Response>;
411
433
  type RuntimeBootstrapResult = {
412
434
  registry: HandlerRegistry;
413
435
  container: Container;
414
436
  /** Create a runtime-compatible handler callback for a specific route. */
415
- createRouteCallback(path: string, method: string): ((err: Error | null, request: Request) => Promise<Response>) | null;
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>;
416
451
  };
417
452
  /**
418
453
  * Bootstrap the user's module and return an object with per-route callback creation.
@@ -430,4 +465,4 @@ type StartRuntimeOptions = {
430
465
  */
431
466
  declare function startRuntime(options?: StartRuntimeOptions): Promise<void>;
432
467
 
433
- 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, runLayerPipeline, startRuntime, tokenToString, validate };
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 };
package/dist/index.d.ts CHANGED
@@ -153,6 +153,7 @@ declare const APP_CONFIG: unique symbol;
153
153
  declare const RUNTIME_APP: unique symbol;
154
154
 
155
155
  type ResolvedHandler = {
156
+ id?: string;
156
157
  path?: string;
157
158
  method?: string;
158
159
  protectedBy: string[];
@@ -200,6 +201,7 @@ declare function registerModuleGraph(graph: ModuleGraph, container: Container):
200
201
  declare class HandlerRegistry {
201
202
  private handlers;
202
203
  getHandler(path: string, method: string): ResolvedHandler | undefined;
204
+ getHandlerById(id: string): ResolvedHandler | undefined;
203
205
  getAllHandlers(): ResolvedHandler[];
204
206
  populateFromGraph(graph: ModuleGraph, container: Container): Promise<void>;
205
207
  scanModule(moduleClass: Type, container: Container): Promise<void>;
@@ -380,6 +382,25 @@ declare class GatewayTimeoutException extends HttpException {
380
382
  constructor(message?: string, details?: unknown);
381
383
  }
382
384
 
385
+ /**
386
+ * Resolve a handler ID as a module reference by dynamically importing
387
+ * the module and matching the exported function against the registry.
388
+ *
389
+ * Resolution strategy:
390
+ * 1. If the ID contains a dot, try splitting at the last dot into
391
+ * `moduleName.exportName` (named export).
392
+ * 2. Fallback: treat the full ID as a module name with a default export.
393
+ * This handles no-dot refs (e.g. "myModule") and dotted module names
394
+ * (e.g. "app.module" from app.module.js) where the named export split failed.
395
+ *
396
+ * Supported formats:
397
+ * - `"handlers.hello"` — named export `hello` from module `handlers`
398
+ * - `"handlers"` — default export from module `handlers`
399
+ * - `"app.module"` — dotted module name: tries named export split first,
400
+ * falls back to default export from module `app.module`
401
+ */
402
+ declare function resolveHandlerByModuleRef(handlerId: string, registry: HandlerRegistry, baseDir: string): Promise<ResolvedHandler | null>;
403
+
383
404
  declare const CONTROLLER_METADATA: unique symbol;
384
405
  declare const HTTP_METHOD_METADATA: unique symbol;
385
406
  declare const ROUTE_PATH_METADATA: unique symbol;
@@ -408,11 +429,25 @@ declare function mapRuntimeRequest(request: Request): HttpRequest;
408
429
  /** Convert SDK HttpResponse → NAPI runtime Response. */
409
430
  declare function mapToRuntimeResponse(response: HttpResponse): Response;
410
431
 
432
+ type RuntimeCallback = (err: Error | null, request: Request) => Promise<Response>;
411
433
  type RuntimeBootstrapResult = {
412
434
  registry: HandlerRegistry;
413
435
  container: Container;
414
436
  /** Create a runtime-compatible handler callback for a specific route. */
415
- createRouteCallback(path: string, method: string): ((err: Error | null, request: Request) => Promise<Response>) | null;
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>;
416
451
  };
417
452
  /**
418
453
  * Bootstrap the user's module and return an object with per-route callback creation.
@@ -430,4 +465,4 @@ type StartRuntimeOptions = {
430
465
  */
431
466
  declare function startRuntime(options?: StartRuntimeOptions): Promise<void>;
432
467
 
433
- 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, runLayerPipeline, startRuntime, tokenToString, validate };
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 };
package/dist/index.js CHANGED
@@ -1055,6 +1055,11 @@ var HandlerRegistry = class {
1055
1055
  debug4("getHandler %s %s \u2192 %s", method, path, found ? "matched" : "not found");
1056
1056
  return found;
1057
1057
  }
1058
+ getHandlerById(id) {
1059
+ const found = this.handlers.find((h) => h.id !== void 0 && h.id === id);
1060
+ debug4("getHandlerById %s \u2192 %s", id, found ? "matched" : "not found");
1061
+ return found;
1062
+ }
1058
1063
  getAllHandlers() {
1059
1064
  return [
1060
1065
  ...this.handlers
@@ -1140,8 +1145,9 @@ var HandlerRegistry = class {
1140
1145
  layers.unshift(validate(schemas));
1141
1146
  }
1142
1147
  }
1143
- debug4("registerFunctionHandler: %s", meta.method && meta.path ? `${meta.method} ${meta.path}` : "(no route)");
1148
+ debug4("registerFunctionHandler: %s", definition.id ?? (meta.method && meta.path ? `${meta.method} ${meta.path}` : "(no route)"));
1144
1149
  this.handlers.push({
1150
+ id: definition.id,
1145
1151
  path: meta.path,
1146
1152
  method: meta.method,
1147
1153
  protectedBy: [],
@@ -1683,23 +1689,96 @@ function httpDelete(path, handlerOrOptions, maybeHandler) {
1683
1689
  }
1684
1690
  __name(httpDelete, "httpDelete");
1685
1691
 
1686
- // src/bootstrap/discovery.ts
1692
+ // src/handlers/module-resolver.ts
1687
1693
  import { resolve } from "path";
1688
1694
  import createDebug9 from "debug";
1689
- var debug9 = createDebug9("celerity:core:bootstrap");
1695
+ var debug9 = createDebug9("celerity:core:module-resolver");
1696
+ async function resolveHandlerByModuleRef(handlerId, registry, baseDir) {
1697
+ const lastDot = handlerId.lastIndexOf(".");
1698
+ if (lastDot > 0) {
1699
+ const moduleName = handlerId.slice(0, lastDot);
1700
+ const exportName = handlerId.slice(lastDot + 1);
1701
+ const result = await tryResolveExport(baseDir, moduleName, exportName, handlerId, registry);
1702
+ if (result) return result;
1703
+ }
1704
+ return tryResolveExport(baseDir, handlerId, "default", handlerId, registry);
1705
+ }
1706
+ __name(resolveHandlerByModuleRef, "resolveHandlerByModuleRef");
1707
+ async function tryResolveExport(baseDir, moduleName, exportName, handlerId, registry) {
1708
+ const handlerModulePath = resolve(baseDir, moduleName);
1709
+ let mod;
1710
+ try {
1711
+ mod = await import(handlerModulePath);
1712
+ } catch {
1713
+ try {
1714
+ mod = await import(`${handlerModulePath}.js`);
1715
+ } catch {
1716
+ return null;
1717
+ }
1718
+ }
1719
+ const exported = mod[exportName];
1720
+ if (!exported) return null;
1721
+ const isFnDef = typeof exported === "object" && exported !== null && exported.__celerity_handler;
1722
+ const handlerFn = isFnDef ? exported.handler : exported;
1723
+ if (typeof handlerFn !== "function") return null;
1724
+ const match = registry.getAllHandlers().find((h) => h.handlerFn === handlerFn);
1725
+ if (match) {
1726
+ match.id = handlerId;
1727
+ debug9("matched '%s' to registry handler", handlerId);
1728
+ return match;
1729
+ }
1730
+ debug9("'%s' not in registry, wrapping directly", handlerId);
1731
+ return buildResolvedFromExport(handlerId, handlerFn, isFnDef ? exported : null);
1732
+ }
1733
+ __name(tryResolveExport, "tryResolveExport");
1734
+ function buildResolvedFromExport(handlerId, handlerFn, fnDef) {
1735
+ if (fnDef) {
1736
+ const meta = fnDef.metadata;
1737
+ return {
1738
+ id: handlerId,
1739
+ protectedBy: [],
1740
+ layers: [
1741
+ ...meta.layers ?? []
1742
+ ],
1743
+ isPublic: false,
1744
+ paramMetadata: [],
1745
+ customMetadata: meta.customMetadata ?? {},
1746
+ handlerFn,
1747
+ isFunctionHandler: true,
1748
+ injectTokens: meta.inject ?? []
1749
+ };
1750
+ }
1751
+ return {
1752
+ id: handlerId,
1753
+ protectedBy: [],
1754
+ layers: [],
1755
+ isPublic: false,
1756
+ paramMetadata: [],
1757
+ customMetadata: {},
1758
+ handlerFn,
1759
+ isFunctionHandler: true,
1760
+ injectTokens: []
1761
+ };
1762
+ }
1763
+ __name(buildResolvedFromExport, "buildResolvedFromExport");
1764
+
1765
+ // src/bootstrap/discovery.ts
1766
+ import { resolve as resolve2 } from "path";
1767
+ import createDebug10 from "debug";
1768
+ var debug10 = createDebug10("celerity:core:bootstrap");
1690
1769
  async function discoverModule(modulePath) {
1691
1770
  const resolved = modulePath ?? process.env.CELERITY_MODULE_PATH;
1692
1771
  if (!resolved) {
1693
1772
  throw new Error("Cannot discover module: set CELERITY_MODULE_PATH environment variable or pass modulePath");
1694
1773
  }
1695
- const absolutePath = resolve(resolved);
1696
- debug9("discoverModule: importing %s", absolutePath);
1774
+ const absolutePath = resolve2(resolved);
1775
+ debug10("discoverModule: importing %s", absolutePath);
1697
1776
  const imported = await import(absolutePath);
1698
1777
  const rootModule = imported.default ?? findModuleExport(imported);
1699
1778
  if (!rootModule || typeof rootModule !== "function") {
1700
1779
  throw new Error(`No module class found in "${resolved}"`);
1701
1780
  }
1702
- debug9("discoverModule: found %s", rootModule.name);
1781
+ debug10("discoverModule: found %s", rootModule.name);
1703
1782
  return rootModule;
1704
1783
  }
1705
1784
  __name(discoverModule, "discoverModule");
@@ -1755,24 +1834,37 @@ function mapToRuntimeResponse(response) {
1755
1834
  __name(mapToRuntimeResponse, "mapToRuntimeResponse");
1756
1835
 
1757
1836
  // src/bootstrap/runtime-entry.ts
1837
+ import { resolve as resolve3, dirname } from "path";
1758
1838
  async function bootstrapForRuntime(modulePath, systemLayers) {
1759
1839
  const layers = systemLayers ?? await createDefaultSystemLayers();
1840
+ const resolvedModulePath = modulePath ?? process.env.CELERITY_MODULE_PATH;
1841
+ const moduleDir = resolvedModulePath ? dirname(resolve3(resolvedModulePath)) : process.cwd();
1760
1842
  const rootModule = await discoverModule(modulePath);
1761
1843
  const { container, registry } = await bootstrap(rootModule);
1844
+ function buildCallback(handler) {
1845
+ if (!handler) return null;
1846
+ return async (_err, request) => {
1847
+ const httpRequest = mapRuntimeRequest(request);
1848
+ const httpResponse = await executeHandlerPipeline(handler, httpRequest, {
1849
+ container,
1850
+ systemLayers: layers
1851
+ });
1852
+ return mapToRuntimeResponse(httpResponse);
1853
+ };
1854
+ }
1855
+ __name(buildCallback, "buildCallback");
1762
1856
  return {
1763
1857
  registry,
1764
1858
  container,
1765
1859
  createRouteCallback(path, method) {
1766
- const handler = registry.getHandler(path, method);
1767
- if (!handler) return null;
1768
- return async (_err, request) => {
1769
- const httpRequest = mapRuntimeRequest(request);
1770
- const httpResponse = await executeHandlerPipeline(handler, httpRequest, {
1771
- container,
1772
- systemLayers: layers
1773
- });
1774
- return mapToRuntimeResponse(httpResponse);
1775
- };
1860
+ return buildCallback(registry.getHandler(path, method));
1861
+ },
1862
+ async createRouteCallbackById(handlerId, codeLocation) {
1863
+ const fromRegistry = registry.getHandlerById(handlerId);
1864
+ if (fromRegistry) return buildCallback(fromRegistry);
1865
+ const baseDir = codeLocation ? resolve3(codeLocation) : moduleDir;
1866
+ const resolved = await resolveHandlerByModuleRef(handlerId, registry, baseDir);
1867
+ return resolved ? buildCallback(resolved) : null;
1776
1868
  }
1777
1869
  };
1778
1870
  }
@@ -1787,7 +1879,7 @@ async function startRuntime(options) {
1787
1879
  const appConfig = app.setup();
1788
1880
  const result = await bootstrapForRuntime();
1789
1881
  for (const def of appConfig.api?.http?.handlers ?? []) {
1790
- const callback = result.createRouteCallback(def.path, def.method);
1882
+ const callback = result.createRouteCallback(def.path, def.method) ?? await result.createRouteCallbackById(def.handler, def.location);
1791
1883
  if (callback) {
1792
1884
  app.registerHttpHandler(def.path, def.method, def.timeout, callback);
1793
1885
  }
@@ -1877,6 +1969,7 @@ export {
1877
1969
  mapToRuntimeResponse,
1878
1970
  mockRequest,
1879
1971
  registerModuleGraph,
1972
+ resolveHandlerByModuleRef,
1880
1973
  runLayerPipeline,
1881
1974
  startRuntime,
1882
1975
  tokenToString,