@celerity-sdk/core 0.2.1 → 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
@@ -382,6 +382,25 @@ declare class GatewayTimeoutException extends HttpException {
382
382
  constructor(message?: string, details?: unknown);
383
383
  }
384
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
+
385
404
  declare const CONTROLLER_METADATA: unique symbol;
386
405
  declare const HTTP_METHOD_METADATA: unique symbol;
387
406
  declare const ROUTE_PATH_METADATA: unique symbol;
@@ -416,8 +435,19 @@ type RuntimeBootstrapResult = {
416
435
  container: Container;
417
436
  /** Create a runtime-compatible handler callback for a specific route. */
418
437
  createRouteCallback(path: string, method: string): RuntimeCallback | null;
419
- /** Create a runtime-compatible handler callback by handler ID (blueprint handler field). */
420
- createRouteCallbackById(handlerId: 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>;
421
451
  };
422
452
  /**
423
453
  * Bootstrap the user's module and return an object with per-route callback creation.
@@ -435,4 +465,4 @@ type StartRuntimeOptions = {
435
465
  */
436
466
  declare function startRuntime(options?: StartRuntimeOptions): Promise<void>;
437
467
 
438
- 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
@@ -382,6 +382,25 @@ declare class GatewayTimeoutException extends HttpException {
382
382
  constructor(message?: string, details?: unknown);
383
383
  }
384
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
+
385
404
  declare const CONTROLLER_METADATA: unique symbol;
386
405
  declare const HTTP_METHOD_METADATA: unique symbol;
387
406
  declare const ROUTE_PATH_METADATA: unique symbol;
@@ -416,8 +435,19 @@ type RuntimeBootstrapResult = {
416
435
  container: Container;
417
436
  /** Create a runtime-compatible handler callback for a specific route. */
418
437
  createRouteCallback(path: string, method: string): RuntimeCallback | null;
419
- /** Create a runtime-compatible handler callback by handler ID (blueprint handler field). */
420
- createRouteCallbackById(handlerId: 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>;
421
451
  };
422
452
  /**
423
453
  * Bootstrap the user's module and return an object with per-route callback creation.
@@ -435,4 +465,4 @@ type StartRuntimeOptions = {
435
465
  */
436
466
  declare function startRuntime(options?: StartRuntimeOptions): Promise<void>;
437
467
 
438
- 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
@@ -1689,23 +1689,96 @@ function httpDelete(path, handlerOrOptions, maybeHandler) {
1689
1689
  }
1690
1690
  __name(httpDelete, "httpDelete");
1691
1691
 
1692
- // src/bootstrap/discovery.ts
1692
+ // src/handlers/module-resolver.ts
1693
1693
  import { resolve } from "path";
1694
1694
  import createDebug9 from "debug";
1695
- 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");
1696
1769
  async function discoverModule(modulePath) {
1697
1770
  const resolved = modulePath ?? process.env.CELERITY_MODULE_PATH;
1698
1771
  if (!resolved) {
1699
1772
  throw new Error("Cannot discover module: set CELERITY_MODULE_PATH environment variable or pass modulePath");
1700
1773
  }
1701
- const absolutePath = resolve(resolved);
1702
- debug9("discoverModule: importing %s", absolutePath);
1774
+ const absolutePath = resolve2(resolved);
1775
+ debug10("discoverModule: importing %s", absolutePath);
1703
1776
  const imported = await import(absolutePath);
1704
1777
  const rootModule = imported.default ?? findModuleExport(imported);
1705
1778
  if (!rootModule || typeof rootModule !== "function") {
1706
1779
  throw new Error(`No module class found in "${resolved}"`);
1707
1780
  }
1708
- debug9("discoverModule: found %s", rootModule.name);
1781
+ debug10("discoverModule: found %s", rootModule.name);
1709
1782
  return rootModule;
1710
1783
  }
1711
1784
  __name(discoverModule, "discoverModule");
@@ -1761,8 +1834,11 @@ function mapToRuntimeResponse(response) {
1761
1834
  __name(mapToRuntimeResponse, "mapToRuntimeResponse");
1762
1835
 
1763
1836
  // src/bootstrap/runtime-entry.ts
1837
+ import { resolve as resolve3, dirname } from "path";
1764
1838
  async function bootstrapForRuntime(modulePath, systemLayers) {
1765
1839
  const layers = systemLayers ?? await createDefaultSystemLayers();
1840
+ const resolvedModulePath = modulePath ?? process.env.CELERITY_MODULE_PATH;
1841
+ const moduleDir = resolvedModulePath ? dirname(resolve3(resolvedModulePath)) : process.cwd();
1766
1842
  const rootModule = await discoverModule(modulePath);
1767
1843
  const { container, registry } = await bootstrap(rootModule);
1768
1844
  function buildCallback(handler) {
@@ -1783,8 +1859,12 @@ async function bootstrapForRuntime(modulePath, systemLayers) {
1783
1859
  createRouteCallback(path, method) {
1784
1860
  return buildCallback(registry.getHandler(path, method));
1785
1861
  },
1786
- createRouteCallbackById(handlerId) {
1787
- return buildCallback(registry.getHandlerById(handlerId));
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;
1788
1868
  }
1789
1869
  };
1790
1870
  }
@@ -1799,7 +1879,7 @@ async function startRuntime(options) {
1799
1879
  const appConfig = app.setup();
1800
1880
  const result = await bootstrapForRuntime();
1801
1881
  for (const def of appConfig.api?.http?.handlers ?? []) {
1802
- const callback = result.createRouteCallback(def.path, def.method) ?? result.createRouteCallbackById(def.handler);
1882
+ const callback = result.createRouteCallback(def.path, def.method) ?? await result.createRouteCallbackById(def.handler, def.location);
1803
1883
  if (callback) {
1804
1884
  app.registerHttpHandler(def.path, def.method, def.timeout, callback);
1805
1885
  }
@@ -1889,6 +1969,7 @@ export {
1889
1969
  mapToRuntimeResponse,
1890
1970
  mockRequest,
1891
1971
  registerModuleGraph,
1972
+ resolveHandlerByModuleRef,
1892
1973
  runLayerPipeline,
1893
1974
  startRuntime,
1894
1975
  tokenToString,