adorn-api 1.0.1 → 1.0.3

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.
Files changed (139) hide show
  1. package/README.md +4 -1
  2. package/dist/adapters/express/createApp.d.ts +149 -11
  3. package/dist/adapters/express/createApp.d.ts.map +1 -1
  4. package/dist/adapters/express/createApp.js +112 -6
  5. package/dist/adapters/express/createApp.js.map +1 -1
  6. package/dist/adapters/express/middleware/errorHandler.d.ts +193 -2
  7. package/dist/adapters/express/middleware/errorHandler.d.ts.map +1 -1
  8. package/dist/adapters/express/middleware/errorHandler.js +164 -3
  9. package/dist/adapters/express/middleware/errorHandler.js.map +1 -1
  10. package/dist/adapters/express/router.d.ts +1 -1
  11. package/dist/adapters/express/router.d.ts.map +1 -1
  12. package/dist/adapters/express/router.js +6 -4
  13. package/dist/adapters/express/router.js.map +1 -1
  14. package/dist/adapters/express/transport/request.js.map +1 -1
  15. package/dist/adapters/express/transport/response.d.ts +1 -1
  16. package/dist/adapters/express/transport/response.d.ts.map +1 -1
  17. package/dist/adapters/express/transport/response.js.map +1 -1
  18. package/dist/contracts/openapi-v3.d.ts +461 -0
  19. package/dist/contracts/openapi-v3.d.ts.map +1 -1
  20. package/dist/contracts/reply.d.ts +109 -1
  21. package/dist/contracts/reply.d.ts.map +1 -1
  22. package/dist/contracts/reply.js +40 -1
  23. package/dist/contracts/reply.js.map +1 -1
  24. package/dist/contracts/response-types.d.ts +5 -5
  25. package/dist/contracts/response-types.d.ts.map +1 -1
  26. package/dist/contracts/responses.d.ts +84 -4
  27. package/dist/contracts/responses.d.ts.map +1 -1
  28. package/dist/contracts/route-options.d.ts +134 -3
  29. package/dist/contracts/route-options.d.ts.map +1 -1
  30. package/dist/contracts/validator.d.ts +121 -0
  31. package/dist/contracts/validator.d.ts.map +1 -1
  32. package/dist/core/binding/binder.d.ts +56 -1
  33. package/dist/core/binding/binder.d.ts.map +1 -1
  34. package/dist/core/binding/binder.js +33 -0
  35. package/dist/core/binding/binder.js.map +1 -1
  36. package/dist/core/binding/coerce/primitives.d.ts +68 -1
  37. package/dist/core/binding/coerce/primitives.d.ts.map +1 -1
  38. package/dist/core/binding/coerce/primitives.js +82 -12
  39. package/dist/core/binding/coerce/primitives.js.map +1 -1
  40. package/dist/core/errors/http-error.d.ts +54 -0
  41. package/dist/core/errors/http-error.d.ts.map +1 -1
  42. package/dist/core/errors/http-error.js +54 -0
  43. package/dist/core/errors/http-error.js.map +1 -1
  44. package/dist/core/errors/validation-error.d.ts +65 -0
  45. package/dist/core/errors/validation-error.d.ts.map +1 -1
  46. package/dist/core/errors/validation-error.js +65 -0
  47. package/dist/core/errors/validation-error.js.map +1 -1
  48. package/dist/core/openapi/buildOpenApi.d.ts +65 -0
  49. package/dist/core/openapi/buildOpenApi.d.ts.map +1 -1
  50. package/dist/core/openapi/buildOpenApi.js +66 -4
  51. package/dist/core/openapi/buildOpenApi.js.map +1 -1
  52. package/dist/core/openapi/schema/registry.d.ts +1 -1
  53. package/dist/core/openapi/schema/registry.d.ts.map +1 -1
  54. package/dist/core/openapi/schema/registry.js.map +1 -1
  55. package/dist/core/registry/buildRegistry.d.ts.map +1 -1
  56. package/dist/core/registry/buildRegistry.js +49 -5
  57. package/dist/core/registry/buildRegistry.js.map +1 -1
  58. package/dist/core/registry/types.d.ts +194 -1
  59. package/dist/core/registry/types.d.ts.map +1 -1
  60. package/dist/core/reply/reply.d.ts +94 -0
  61. package/dist/core/reply/reply.d.ts.map +1 -1
  62. package/dist/core/reply/reply.js +87 -0
  63. package/dist/core/reply/reply.js.map +1 -1
  64. package/dist/core/reply/typed.d.ts +137 -3
  65. package/dist/core/reply/typed.d.ts.map +1 -1
  66. package/dist/core/reply/typed.js +137 -2
  67. package/dist/core/reply/typed.js.map +1 -1
  68. package/dist/core/responses/helpers.d.ts +1 -1
  69. package/dist/core/responses/helpers.d.ts.map +1 -1
  70. package/dist/core/responses/normalize.d.ts.map +1 -1
  71. package/dist/core/responses/normalize.js +2 -1
  72. package/dist/core/responses/normalize.js.map +1 -1
  73. package/dist/core/route/defineRoute.d.ts +48 -1
  74. package/dist/core/route/defineRoute.d.ts.map +1 -1
  75. package/dist/core/route/defineRoute.js +42 -1
  76. package/dist/core/route/defineRoute.js.map +1 -1
  77. package/dist/decorators/binding.d.ts +1 -1
  78. package/dist/decorators/binding.d.ts.map +1 -1
  79. package/dist/decorators/binding.js.map +1 -1
  80. package/dist/decorators/controller.d.ts +1 -1
  81. package/dist/decorators/controller.d.ts.map +1 -1
  82. package/dist/decorators/controller.js.map +1 -1
  83. package/dist/decorators/docs.d.ts +6 -0
  84. package/dist/decorators/docs.d.ts.map +1 -1
  85. package/dist/decorators/docs.js +45 -2
  86. package/dist/decorators/docs.js.map +1 -1
  87. package/dist/decorators/index.d.ts +3 -0
  88. package/dist/decorators/index.d.ts.map +1 -1
  89. package/dist/decorators/index.js +3 -0
  90. package/dist/decorators/index.js.map +1 -1
  91. package/dist/decorators/methods.d.ts +128 -6
  92. package/dist/decorators/methods.d.ts.map +1 -1
  93. package/dist/decorators/methods.js +124 -0
  94. package/dist/decorators/methods.js.map +1 -1
  95. package/dist/decorators/responses.d.ts +5 -0
  96. package/dist/decorators/responses.d.ts.map +1 -1
  97. package/dist/decorators/responses.js +43 -2
  98. package/dist/decorators/responses.js.map +1 -1
  99. package/dist/decorators/security.d.ts +6 -0
  100. package/dist/decorators/security.d.ts.map +1 -1
  101. package/dist/decorators/security.js +38 -2
  102. package/dist/decorators/security.js.map +1 -1
  103. package/dist/index.d.ts +5 -2
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +17 -2
  106. package/dist/index.js.map +1 -1
  107. package/dist/integrations/metal-orm/schema/column-map.d.ts +91 -0
  108. package/dist/integrations/metal-orm/schema/column-map.d.ts.map +1 -1
  109. package/dist/integrations/metal-orm/schema/column-map.js +129 -2
  110. package/dist/integrations/metal-orm/schema/column-map.js.map +1 -1
  111. package/dist/integrations/metal-orm/schema/dto.d.ts +2 -2
  112. package/dist/integrations/metal-orm/schema/dto.d.ts.map +1 -1
  113. package/dist/integrations/metal-orm/schema/dto.js.map +1 -1
  114. package/dist/integrations/metal-orm/schema/entity.d.ts +90 -8
  115. package/dist/integrations/metal-orm/schema/entity.d.ts.map +1 -1
  116. package/dist/integrations/metal-orm/schema/entity.js +78 -6
  117. package/dist/integrations/metal-orm/schema/entity.js.map +1 -1
  118. package/dist/integrations/metal-orm/schema/filters.d.ts +1 -1
  119. package/dist/integrations/metal-orm/schema/filters.d.ts.map +1 -1
  120. package/dist/integrations/metal-orm/schema/filters.js +2 -1
  121. package/dist/integrations/metal-orm/schema/filters.js.map +1 -1
  122. package/dist/integrations/metal-orm/schema/tabledef.d.ts +1 -1
  123. package/dist/integrations/metal-orm/schema/tabledef.d.ts.map +1 -1
  124. package/dist/metadata/bag.d.ts +2 -1
  125. package/dist/metadata/bag.d.ts.map +1 -1
  126. package/dist/metadata/bag.js +2 -1
  127. package/dist/metadata/bag.js.map +1 -1
  128. package/dist/metadata/keys.d.ts +203 -1
  129. package/dist/metadata/keys.d.ts.map +1 -1
  130. package/dist/metadata/keys.js +3 -9
  131. package/dist/metadata/keys.js.map +1 -1
  132. package/dist/metadata/merge.d.ts.map +1 -1
  133. package/dist/metadata/merge.js +4 -1
  134. package/dist/metadata/merge.js.map +1 -1
  135. package/dist/validation/native/schema.d.ts +2 -2
  136. package/dist/validation/native/schema.d.ts.map +1 -1
  137. package/dist/validation/native/validator.d.ts +1 -1
  138. package/dist/validation/native/validator.d.ts.map +1 -1
  139. package/package.json +6 -2
package/README.md CHANGED
@@ -9,15 +9,18 @@ Adorn API turns TypeScript classes into HTTP controllers with Stage-3 decorators
9
9
 
10
10
  ## Features
11
11
  - Controller decorators (`@Controller`, `@Get`, `@Post`, etc.) backed by a registry/router that mounts on Express.
12
+ - `createAdornExpressRouter` and `buildRegistry` for mounting Adorn into existing Express stacks.
13
+ - Problem Details error handling with an `onError` hook for custom shapes/logging.
12
14
  - Built-in OpenAPI generator with optional Swagger UI serving through the Express adapter.
13
15
  - MetalORM helpers (`entityDto`, `filtersFromEntity`, `tableDefOf`) to reuse entity metadata for payload validation and database filtering.
14
16
  - End-to-end coverage for both direct API handlers and MetalORM REST routes using Vitest + Supertest.
15
17
 
16
- For detailed writeups of each feature, see the companion guides under `docs/`.
18
+ For detailed writeups of each feature, see the companion guides under `docs/` (including the Stage-3 decorator setup).
17
19
 
18
20
  ## Requirements
19
21
  - Node.js v18+
20
22
  - SQLite (only for in-memory tests; runtime persistence is pluggable via MetalORM executors)
23
+ - TypeScript 5.x with Stage-3 decorators (do not enable `experimentalDecorators`)
21
24
 
22
25
  ## Getting started
23
26
  1. `npm install` to pull runtime and dev dependencies (Express, MetalORM, Vitest).
@@ -1,20 +1,158 @@
1
- import { type Express } from 'express';
2
- import type { ControllerCtor } from '../../core/registry/types.js';
1
+ import { type Express, type Router } from 'express';
2
+ import type { ControllerCtor, Registry } from '../../core/registry/types.js';
3
3
  import type { Validator } from '../../contracts/validator.js';
4
4
  import { type ApplyRoutesOptions } from './router.js';
5
+ import { type AdornErrorHandlerOptions } from './middleware/errorHandler.js';
5
6
  import type { OpenApiBuildOptions } from '../../core/openapi/buildOpenApi.js';
6
- export type CreateAdornExpressAppOptions = ApplyRoutesOptions & {
7
+ /**
8
+ * Options for OpenAPI documentation generation and serving.
9
+ * Extends OpenApiBuildOptions with serving configuration.
10
+ */
11
+ export type AdornOpenApiOptions = OpenApiBuildOptions & {
12
+ /** Whether to enable OpenAPI documentation (default: true) */
13
+ enabled?: boolean;
14
+ /** Path to serve the OpenAPI JSON specification (default: '/openapi.json') */
15
+ jsonPath?: string;
16
+ /** Path to serve the OpenAPI documentation UI (default: '/docs') */
17
+ docsPath?: string;
18
+ /** Whether to serve Swagger UI (default: true) */
19
+ swaggerUi?: boolean;
20
+ /** Configuration options for Swagger UI */
21
+ swaggerUiConfig?: Record<string, unknown>;
22
+ };
23
+ /**
24
+ * Options for creating an Adorn Express router with controllers.
25
+ *
26
+ * @see ApplyRoutesOptions for additional routing options
27
+ */
28
+ export type CreateAdornExpressRouterOptions = ApplyRoutesOptions & {
29
+ /** Array of controller constructors to register */
7
30
  controllers: ControllerCtor[];
8
- mountPath?: string;
31
+ /** Whether to automatically add JSON body parser middleware (default: true) */
9
32
  jsonBodyParser?: boolean;
33
+ /** Validator instance for request validation */
10
34
  validator?: Validator;
11
- openapi?: (OpenApiBuildOptions & {
12
- enabled?: boolean;
13
- jsonPath?: string;
14
- docsPath?: string;
15
- swaggerUi?: boolean;
16
- swaggerUiConfig?: Record<string, unknown>;
17
- });
35
+ /** Error handler configuration or false to disable (default: built-in handler) */
36
+ errorHandler?: AdornErrorHandlerOptions | false;
37
+ /** OpenAPI documentation configuration */
38
+ openapi?: AdornOpenApiOptions;
39
+ };
40
+ /**
41
+ * Result of creating an Adorn Express router.
42
+ */
43
+ export type CreateAdornExpressRouterResult = {
44
+ /** Configured Express router with all routes */
45
+ router: Router;
46
+ /** Route registry containing metadata about all registered routes */
47
+ registry: Registry;
48
+ };
49
+ /**
50
+ * Options for creating an Adorn Express application.
51
+ * Extends router options with mount path configuration.
52
+ *
53
+ * @see CreateAdornExpressRouterOptions for base options
54
+ */
55
+ export type CreateAdornExpressAppOptions = CreateAdornExpressRouterOptions & {
56
+ /** Path to mount the router (default: '/') */
57
+ mountPath?: string;
18
58
  };
59
+ /**
60
+ * Creates a complete Express application with Adorn API functionality.
61
+ *
62
+ * This function sets up an Express app with all Adorn features including:
63
+ * - Controller-based routing
64
+ * - Automatic OpenAPI documentation
65
+ * - Built-in error handling
66
+ * - Request validation
67
+ *
68
+ * @param options - Configuration options for the application
69
+ * @returns Configured Express application instance
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { createAdornExpressApp } from '@adorn/api';
74
+ * import { UserController } from './controllers/user.controller';
75
+ *
76
+ * const app = createAdornExpressApp({
77
+ * controllers: [UserController],
78
+ * openapi: {
79
+ * title: 'My API',
80
+ * version: '1.0.0'
81
+ * }
82
+ * });
83
+ *
84
+ * app.listen(3000, () => {
85
+ * console.log('Server running on port 3000');
86
+ * });
87
+ * ```
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * // With custom mount path
92
+ * const app = createAdornExpressApp({
93
+ * controllers: [UserController, ProductController],
94
+ * mountPath: '/api/v1',
95
+ * jsonBodyParser: true,
96
+ * errorHandler: {
97
+ * logErrors: true,
98
+ * exposeStack: process.env.NODE_ENV === 'development'
99
+ * }
100
+ * });
101
+ * ```
102
+ *
103
+ * @see createAdornExpressRouter for router-specific functionality
104
+ * @see AdornOpenApiOptions for OpenAPI configuration
105
+ */
19
106
  export declare function createAdornExpressApp(options: CreateAdornExpressAppOptions): Express;
107
+ /**
108
+ * Creates an Express router with Adorn API functionality.
109
+ *
110
+ * This function sets up an Express router with all Adorn features including:
111
+ * - Controller-based routing
112
+ * - Automatic OpenAPI documentation
113
+ * - Built-in error handling
114
+ * - Request validation
115
+ *
116
+ * @param options - Configuration options for the router
117
+ * @returns Object containing the configured router and route registry
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * import { createAdornExpressRouter } from '@adorn/api';
122
+ * import { UserController } from './controllers/user.controller';
123
+ * import express from 'express';
124
+ *
125
+ * const app = express();
126
+ * const { router, registry } = createAdornExpressRouter({
127
+ * controllers: [UserController],
128
+ * openapi: {
129
+ * title: 'My API',
130
+ * version: '1.0.0',
131
+ * docsPath: '/api-docs'
132
+ * }
133
+ * });
134
+ *
135
+ * app.use('/api', router);
136
+ *
137
+ * // Access the registry for runtime inspection
138
+ * console.log('Registered routes:', registry.routes.length);
139
+ * ```
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * // With custom validator and error handling
144
+ * const { router } = createAdornExpressRouter({
145
+ * controllers: [UserController],
146
+ * validator: new CustomValidator(),
147
+ * errorHandler: {
148
+ * logErrors: true,
149
+ * customErrorFormatter: (err) => ({ ...err, timestamp: new Date() })
150
+ * }
151
+ * });
152
+ * ```
153
+ *
154
+ * @see createAdornExpressApp for full application setup
155
+ * @see AdornOpenApiOptions for OpenAPI configuration
156
+ */
157
+ export declare function createAdornExpressRouter(options: CreateAdornExpressRouterOptions): CreateAdornExpressRouterResult;
20
158
  //# sourceMappingURL=createApp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createApp.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/createApp.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAgC,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAG9E,MAAM,MAAM,4BAA4B,GAAG,kBAAkB,GAAG;IAC9D,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,OAAO,CAAC,EAAE,CAAC,mBAAmB,GAAG;QAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3C,CAAC,CAAC;CACJ,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAyCpF"}
1
+ {"version":3,"file":"createApp.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/createApp.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAgC,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAG9E;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG;IACtD,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,+BAA+B,GAAG,kBAAkB,GAAG;IACjE,mDAAmD;IACnD,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gDAAgD;IAChD,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,kFAAkF;IAClF,YAAY,CAAC,EAAE,wBAAwB,GAAG,KAAK,CAAC;IAChD,0CAA0C;IAC1C,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,4BAA4B,GAAG,+BAA+B,GAAG;IAC3E,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAKpF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,+BAA+B,GACvC,8BAA8B,CAqChC"}
@@ -1,15 +1,117 @@
1
1
  import express, {} from 'express';
2
2
  import { buildRegistry } from '../../core/registry/buildRegistry.js';
3
3
  import { applyRegistryToExpressRouter } from './router.js';
4
- import { adornErrorHandler } from './middleware/errorHandler.js';
4
+ import { adornErrorHandler, createAdornExpressErrorHandler, } from './middleware/errorHandler.js';
5
5
  import { serveOpenApi } from './swagger/serve.js';
6
+ /**
7
+ * Creates a complete Express application with Adorn API functionality.
8
+ *
9
+ * This function sets up an Express app with all Adorn features including:
10
+ * - Controller-based routing
11
+ * - Automatic OpenAPI documentation
12
+ * - Built-in error handling
13
+ * - Request validation
14
+ *
15
+ * @param options - Configuration options for the application
16
+ * @returns Configured Express application instance
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { createAdornExpressApp } from '@adorn/api';
21
+ * import { UserController } from './controllers/user.controller';
22
+ *
23
+ * const app = createAdornExpressApp({
24
+ * controllers: [UserController],
25
+ * openapi: {
26
+ * title: 'My API',
27
+ * version: '1.0.0'
28
+ * }
29
+ * });
30
+ *
31
+ * app.listen(3000, () => {
32
+ * console.log('Server running on port 3000');
33
+ * });
34
+ * ```
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // With custom mount path
39
+ * const app = createAdornExpressApp({
40
+ * controllers: [UserController, ProductController],
41
+ * mountPath: '/api/v1',
42
+ * jsonBodyParser: true,
43
+ * errorHandler: {
44
+ * logErrors: true,
45
+ * exposeStack: process.env.NODE_ENV === 'development'
46
+ * }
47
+ * });
48
+ * ```
49
+ *
50
+ * @see createAdornExpressRouter for router-specific functionality
51
+ * @see AdornOpenApiOptions for OpenAPI configuration
52
+ */
6
53
  export function createAdornExpressApp(options) {
7
54
  const app = express();
55
+ const { router } = createAdornExpressRouter(options);
56
+ app.use(options.mountPath ?? '/', router);
57
+ return app;
58
+ }
59
+ /**
60
+ * Creates an Express router with Adorn API functionality.
61
+ *
62
+ * This function sets up an Express router with all Adorn features including:
63
+ * - Controller-based routing
64
+ * - Automatic OpenAPI documentation
65
+ * - Built-in error handling
66
+ * - Request validation
67
+ *
68
+ * @param options - Configuration options for the router
69
+ * @returns Object containing the configured router and route registry
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { createAdornExpressRouter } from '@adorn/api';
74
+ * import { UserController } from './controllers/user.controller';
75
+ * import express from 'express';
76
+ *
77
+ * const app = express();
78
+ * const { router, registry } = createAdornExpressRouter({
79
+ * controllers: [UserController],
80
+ * openapi: {
81
+ * title: 'My API',
82
+ * version: '1.0.0',
83
+ * docsPath: '/api-docs'
84
+ * }
85
+ * });
86
+ *
87
+ * app.use('/api', router);
88
+ *
89
+ * // Access the registry for runtime inspection
90
+ * console.log('Registered routes:', registry.routes.length);
91
+ * ```
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * // With custom validator and error handling
96
+ * const { router } = createAdornExpressRouter({
97
+ * controllers: [UserController],
98
+ * validator: new CustomValidator(),
99
+ * errorHandler: {
100
+ * logErrors: true,
101
+ * customErrorFormatter: (err) => ({ ...err, timestamp: new Date() })
102
+ * }
103
+ * });
104
+ * ```
105
+ *
106
+ * @see createAdornExpressApp for full application setup
107
+ * @see AdornOpenApiOptions for OpenAPI configuration
108
+ */
109
+ export function createAdornExpressRouter(options) {
110
+ const router = express.Router();
8
111
  if (options.jsonBodyParser ?? true) {
9
- app.use(express.json());
112
+ router.use(express.json());
10
113
  }
11
114
  const registry = buildRegistry(options.controllers);
12
- const router = express.Router();
13
115
  applyRegistryToExpressRouter(router, registry, options);
14
116
  const oa = options.openapi;
15
117
  if (oa?.enabled ?? true) {
@@ -28,8 +130,12 @@ export function createAdornExpressApp(options) {
28
130
  router.use(serveOpenApi(registry, openApiOptions, serveOptions));
29
131
  }
30
132
  }
31
- app.use(options.mountPath ?? '/', router);
32
- app.use(adornErrorHandler);
33
- return app;
133
+ if (options.errorHandler !== false) {
134
+ const handler = options.errorHandler
135
+ ? createAdornExpressErrorHandler(options.errorHandler)
136
+ : adornErrorHandler;
137
+ router.use(handler);
138
+ }
139
+ return { router, registry };
34
140
  }
35
141
  //# sourceMappingURL=createApp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createApp.js","sourceRoot":"","sources":["../../../src/adapters/express/createApp.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAgB,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAA2B,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiBlD,MAAM,UAAU,qBAAqB,CAAC,OAAqC;IACzE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IAEtB,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAChC,4BAA4B,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExD,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAC3B,IAAI,EAAE,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,EAAE,EAAE,KAAK,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC;YAC7B,MAAM,cAAc,GAAwB;gBAC1C,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,OAAO,EAAE,EAAE,CAAC,OAAO;gBACnB,GAAG,CAAC,EAAE,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7D,CAAC;YACF,MAAM,YAAY,GAAG;gBACnB,GAAG,CAAC,EAAE,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,EAAE,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,EAAE,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClE,GAAG,CAAC,EAAE,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrF,CAAC;YAEF,MAAM,CAAC,GAAG,CACR,YAAY,CACV,QAAQ,EACR,cAAc,EACd,YAAY,CACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1C,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAE3B,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"createApp.js","sourceRoot":"","sources":["../../../src/adapters/express/createApp.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,194 @@
1
- import type { NextFunction, Request, Response } from 'express';
2
- export declare function adornErrorHandler(err: unknown, req: Request, res: Response, _next: NextFunction): void;
1
+ import type { ErrorRequestHandler, Request, Response } from 'express';
2
+ import type { ProblemDetails } from '../../../contracts/errors.js';
3
+ /**
4
+ * Context object provided to custom error handlers.
5
+ *
6
+ * Contains the Express request and response objects, the request path,
7
+ * and the default problem details that would be returned.
8
+ */
9
+ export type AdornErrorHandlerContext = {
10
+ /** Express request object */
11
+ req: Request;
12
+ /** Express response object */
13
+ res: Response;
14
+ /** Request path/URL */
15
+ instance: string;
16
+ /** Default problem details that would be returned */
17
+ defaultProblem: ProblemDetails;
18
+ };
19
+ /**
20
+ * Result types that can be returned from a custom error handler.
21
+ *
22
+ * Supports returning ProblemDetails, custom responses, or void (to use default).
23
+ */
24
+ export type AdornErrorHandlerResult = ProblemDetails | {
25
+ status: number;
26
+ body: unknown;
27
+ headers?: Record<string, string>;
28
+ } | void;
29
+ /**
30
+ * Options for configuring the Adorn error handler.
31
+ *
32
+ * Allows customization of error handling behavior through the onError callback.
33
+ */
34
+ export type AdornErrorHandlerOptions = {
35
+ /**
36
+ * Custom error handler function.
37
+ *
38
+ * @param err - The error that occurred
39
+ * @param ctx - Error handler context with request/response info
40
+ * @returns Custom error response, problem details, or void to use default
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Custom error formatting
45
+ * onError: (err, ctx) => {
46
+ * if (err instanceof ValidationError) {
47
+ * return {
48
+ * status: 400,
49
+ * body: {
50
+ * success: false,
51
+ * errors: err.issues,
52
+ * timestamp: new Date().toISOString()
53
+ * }
54
+ * };
55
+ * }
56
+ * return ctx.defaultProblem; // Use default for other errors
57
+ * }
58
+ * ```
59
+ */
60
+ onError?: (err: unknown, ctx: AdornErrorHandlerContext) => AdornErrorHandlerResult;
61
+ };
62
+ /**
63
+ * Default Adorn error handler for Express applications.
64
+ *
65
+ * This is the built-in error handler that converts errors to appropriate
66
+ * HTTP responses. It handles HttpError, ValidationError, and other errors
67
+ * by converting them to Problem Details format.
68
+ *
69
+ * @param err - The error that occurred
70
+ * @param req - Express request object
71
+ * @param res - Express response object
72
+ * @param next - Express next function
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * // Basic usage in Express app
77
+ * import { adornErrorHandler } from '@adorn/api';
78
+ *
79
+ * const app = express();
80
+ * // ... routes and middleware
81
+ * app.use(adornErrorHandler); // Use as last middleware
82
+ * ```
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // With custom error handling
87
+ * app.use((err, req, res, next) => {
88
+ * // Custom logging
89
+ * console.error('Error occurred:', err);
90
+ *
91
+ * // Use adorn error handler
92
+ * adornErrorHandler(err, req, res, next);
93
+ * });
94
+ * ```
95
+ *
96
+ * @see createAdornExpressErrorHandler for customizable error handler
97
+ * @see HttpError for HTTP error class
98
+ */
99
+ export declare function adornErrorHandler(err: unknown, req: Request, res: Response, next: Parameters<ErrorRequestHandler>[3]): unknown;
100
+ /**
101
+ * Creates a customizable Adorn error handler for Express applications.
102
+ *
103
+ * This function allows customization of error handling behavior while
104
+ * maintaining the core functionality of converting errors to appropriate
105
+ * HTTP responses.
106
+ *
107
+ * @param options - Error handler configuration options
108
+ * @returns Express error request handler function
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * // Basic custom error handler
113
+ * const errorHandler = createAdornExpressErrorHandler({
114
+ * onError: (err, ctx) => {
115
+ * // Add custom logging
116
+ * console.error('Error:', err.message, 'Path:', ctx.instance);
117
+ *
118
+ * // Return default problem details
119
+ * return ctx.defaultProblem;
120
+ * }
121
+ * });
122
+ *
123
+ * app.use(errorHandler);
124
+ * ```
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * // Advanced error handling with custom responses
129
+ * const errorHandler = createAdornExpressErrorHandler({
130
+ * onError: (err, ctx) => {
131
+ * if (err instanceof ValidationError) {
132
+ * return {
133
+ * status: 400,
134
+ * body: {
135
+ * success: false,
136
+ * type: 'validation_error',
137
+ * issues: err.issues,
138
+ * timestamp: new Date().toISOString(),
139
+ * requestId: ctx.req.id
140
+ * },
141
+ * headers: {
142
+ * 'X-Error-Type': 'validation'
143
+ * }
144
+ * };
145
+ * }
146
+ *
147
+ * if (err instanceof HttpError && err.status === 404) {
148
+ * return {
149
+ * status: 404,
150
+ * body: {
151
+ * success: false,
152
+ * type: 'not_found',
153
+ * message: 'Resource not found',
154
+ * details: err.details
155
+ * }
156
+ * };
157
+ * }
158
+ *
159
+ * // Use default for other errors
160
+ * return ctx.defaultProblem;
161
+ * }
162
+ * });
163
+ *
164
+ * app.use(errorHandler);
165
+ * ```
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * // Error handler with request ID correlation
170
+ * const errorHandler = createAdornExpressErrorHandler({
171
+ * onError: (err, ctx) => {
172
+ * const requestId = ctx.req.headers['x-request-id'] || ctx.req.id;
173
+ *
174
+ * // Add request ID to all error responses
175
+ * const problem = ctx.defaultProblem;
176
+ * return {
177
+ * ...problem,
178
+ * body: {
179
+ * ...problem,
180
+ * requestId,
181
+ * timestamp: new Date().toISOString()
182
+ * }
183
+ * };
184
+ * }
185
+ * });
186
+ *
187
+ * app.use(errorHandler);
188
+ * ```
189
+ *
190
+ * @see adornErrorHandler for the default error handler
191
+ * @see AdornErrorHandlerOptions for configuration options
192
+ */
193
+ export declare function createAdornExpressErrorHandler(options?: AdornErrorHandlerOptions): ErrorRequestHandler;
3
194
  //# sourceMappingURL=errorHandler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapters/express/middleware/errorHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG/D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,QAI/F"}
1
+ {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapters/express/middleware/errorHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGnE;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,6BAA6B;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,8BAA8B;IAC9B,GAAG,EAAE,QAAQ,CAAC;IACd,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,cAAc,EAAE,cAAc,CAAC;CAChC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAC/B,cAAc,GACd;IACE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,GACD,IAAI,CAAC;AAET;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,wBAAwB,KAAK,uBAAuB,CAAC;CACpF,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,WAGzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4FG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,wBAA6B,GACrC,mBAAmB,CA+BrB"}