@buenojs/bueno 0.8.4 → 0.8.5

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 (218) hide show
  1. package/README.md +136 -16
  2. package/dist/cli/{index.js → bin.js} +412 -331
  3. package/dist/container/index.js +250 -0
  4. package/dist/context/index.js +219 -0
  5. package/dist/database/index.js +493 -0
  6. package/dist/frontend/index.js +7697 -0
  7. package/dist/health/index.js +364 -0
  8. package/dist/i18n/index.js +345 -0
  9. package/dist/index.js +11043 -6482
  10. package/dist/jobs/index.js +819 -0
  11. package/dist/lock/index.js +367 -0
  12. package/dist/logger/index.js +281 -0
  13. package/dist/metrics/index.js +289 -0
  14. package/dist/middleware/index.js +77 -0
  15. package/dist/migrations/index.js +571 -0
  16. package/dist/modules/index.js +3346 -0
  17. package/dist/notification/index.js +484 -0
  18. package/dist/observability/index.js +331 -0
  19. package/dist/openapi/index.js +776 -0
  20. package/dist/orm/index.js +1356 -0
  21. package/dist/router/index.js +886 -0
  22. package/dist/rpc/index.js +691 -0
  23. package/dist/schema/index.js +400 -0
  24. package/dist/telemetry/index.js +595 -0
  25. package/dist/template/index.js +640 -0
  26. package/dist/templates/index.js +640 -0
  27. package/dist/testing/index.js +1111 -0
  28. package/dist/types/index.js +60 -0
  29. package/package.json +121 -27
  30. package/src/cache/index.ts +2 -1
  31. package/src/cli/bin.ts +2 -2
  32. package/src/cli/commands/build.ts +183 -165
  33. package/src/cli/commands/dev.ts +96 -89
  34. package/src/cli/commands/generate.ts +142 -111
  35. package/src/cli/commands/help.ts +20 -16
  36. package/src/cli/commands/index.ts +3 -6
  37. package/src/cli/commands/migration.ts +124 -105
  38. package/src/cli/commands/new.ts +294 -232
  39. package/src/cli/commands/start.ts +81 -79
  40. package/src/cli/core/args.ts +68 -50
  41. package/src/cli/core/console.ts +89 -95
  42. package/src/cli/core/index.ts +4 -4
  43. package/src/cli/core/prompt.ts +65 -62
  44. package/src/cli/core/spinner.ts +23 -20
  45. package/src/cli/index.ts +46 -38
  46. package/src/cli/templates/database/index.ts +37 -18
  47. package/src/cli/templates/database/mysql.ts +3 -3
  48. package/src/cli/templates/database/none.ts +2 -2
  49. package/src/cli/templates/database/postgresql.ts +3 -3
  50. package/src/cli/templates/database/sqlite.ts +3 -3
  51. package/src/cli/templates/deploy.ts +29 -26
  52. package/src/cli/templates/docker.ts +41 -30
  53. package/src/cli/templates/frontend/index.ts +33 -15
  54. package/src/cli/templates/frontend/none.ts +2 -2
  55. package/src/cli/templates/frontend/react.ts +18 -18
  56. package/src/cli/templates/frontend/solid.ts +15 -15
  57. package/src/cli/templates/frontend/svelte.ts +17 -17
  58. package/src/cli/templates/frontend/vue.ts +15 -15
  59. package/src/cli/templates/generators/index.ts +29 -29
  60. package/src/cli/templates/generators/types.ts +21 -21
  61. package/src/cli/templates/index.ts +6 -6
  62. package/src/cli/templates/project/api.ts +37 -36
  63. package/src/cli/templates/project/default.ts +25 -25
  64. package/src/cli/templates/project/fullstack.ts +28 -26
  65. package/src/cli/templates/project/index.ts +55 -16
  66. package/src/cli/templates/project/minimal.ts +17 -12
  67. package/src/cli/templates/project/types.ts +10 -5
  68. package/src/cli/templates/project/website.ts +14 -14
  69. package/src/cli/utils/fs.ts +55 -41
  70. package/src/cli/utils/index.ts +3 -3
  71. package/src/cli/utils/strings.ts +47 -33
  72. package/src/cli/utils/version.ts +14 -8
  73. package/src/config/env-validation.ts +100 -0
  74. package/src/config/env.ts +169 -41
  75. package/src/config/index.ts +28 -20
  76. package/src/config/loader.ts +25 -16
  77. package/src/config/merge.ts +21 -10
  78. package/src/config/types.ts +545 -25
  79. package/src/config/validation.ts +215 -7
  80. package/src/container/forward-ref.ts +22 -22
  81. package/src/container/index.ts +34 -12
  82. package/src/context/index.ts +11 -1
  83. package/src/database/index.ts +7 -190
  84. package/src/database/orm/builder.ts +457 -0
  85. package/src/database/orm/casts/index.ts +130 -0
  86. package/src/database/orm/casts/types.ts +25 -0
  87. package/src/database/orm/compiler.ts +304 -0
  88. package/src/database/orm/hooks/index.ts +114 -0
  89. package/src/database/orm/index.ts +61 -0
  90. package/src/database/orm/model-registry.ts +59 -0
  91. package/src/database/orm/model.ts +821 -0
  92. package/src/database/orm/relationships/base.ts +146 -0
  93. package/src/database/orm/relationships/belongs-to-many.ts +179 -0
  94. package/src/database/orm/relationships/belongs-to.ts +56 -0
  95. package/src/database/orm/relationships/has-many.ts +45 -0
  96. package/src/database/orm/relationships/has-one.ts +41 -0
  97. package/src/database/orm/relationships/index.ts +11 -0
  98. package/src/database/orm/scopes/index.ts +55 -0
  99. package/src/events/__tests__/event-system.test.ts +235 -0
  100. package/src/events/config.ts +238 -0
  101. package/src/events/example-usage.ts +185 -0
  102. package/src/events/index.ts +278 -0
  103. package/src/events/manager.ts +385 -0
  104. package/src/events/registry.ts +182 -0
  105. package/src/events/types.ts +124 -0
  106. package/src/frontend/api-routes.ts +65 -23
  107. package/src/frontend/bundler.ts +76 -34
  108. package/src/frontend/console-client.ts +2 -2
  109. package/src/frontend/console-stream.ts +94 -38
  110. package/src/frontend/dev-server.ts +94 -46
  111. package/src/frontend/file-router.ts +61 -19
  112. package/src/frontend/frameworks/index.ts +37 -10
  113. package/src/frontend/frameworks/react.ts +10 -8
  114. package/src/frontend/frameworks/solid.ts +11 -9
  115. package/src/frontend/frameworks/svelte.ts +15 -9
  116. package/src/frontend/frameworks/vue.ts +13 -11
  117. package/src/frontend/hmr-client.ts +12 -10
  118. package/src/frontend/hmr.ts +146 -103
  119. package/src/frontend/index.ts +14 -5
  120. package/src/frontend/islands.ts +41 -22
  121. package/src/frontend/isr.ts +59 -37
  122. package/src/frontend/layout.ts +36 -21
  123. package/src/frontend/ssr/react.ts +74 -27
  124. package/src/frontend/ssr/solid.ts +54 -20
  125. package/src/frontend/ssr/svelte.ts +48 -14
  126. package/src/frontend/ssr/vue.ts +50 -18
  127. package/src/frontend/ssr.ts +83 -39
  128. package/src/frontend/types.ts +91 -56
  129. package/src/health/index.ts +21 -9
  130. package/src/i18n/engine.ts +305 -0
  131. package/src/i18n/index.ts +38 -0
  132. package/src/i18n/loader.ts +218 -0
  133. package/src/i18n/middleware.ts +164 -0
  134. package/src/i18n/negotiator.ts +162 -0
  135. package/src/i18n/types.ts +158 -0
  136. package/src/index.ts +179 -27
  137. package/src/jobs/drivers/memory.ts +315 -0
  138. package/src/jobs/drivers/redis.ts +459 -0
  139. package/src/jobs/index.ts +30 -0
  140. package/src/jobs/queue.ts +281 -0
  141. package/src/jobs/types.ts +295 -0
  142. package/src/jobs/worker.ts +380 -0
  143. package/src/logger/index.ts +1 -3
  144. package/src/logger/transports/index.ts +62 -22
  145. package/src/metrics/index.ts +25 -16
  146. package/src/migrations/index.ts +9 -0
  147. package/src/modules/filters.ts +13 -17
  148. package/src/modules/guards.ts +49 -26
  149. package/src/modules/index.ts +409 -298
  150. package/src/modules/interceptors.ts +58 -20
  151. package/src/modules/lazy.ts +11 -19
  152. package/src/modules/lifecycle.ts +15 -7
  153. package/src/modules/metadata.ts +15 -5
  154. package/src/modules/pipes.ts +94 -72
  155. package/src/notification/channels/base.ts +68 -0
  156. package/src/notification/channels/email.ts +105 -0
  157. package/src/notification/channels/push.ts +104 -0
  158. package/src/notification/channels/sms.ts +105 -0
  159. package/src/notification/channels/whatsapp.ts +104 -0
  160. package/src/notification/index.ts +48 -0
  161. package/src/notification/service.ts +354 -0
  162. package/src/notification/types.ts +344 -0
  163. package/src/observability/__tests__/observability.test.ts +483 -0
  164. package/src/observability/breadcrumbs.ts +114 -0
  165. package/src/observability/index.ts +136 -0
  166. package/src/observability/interceptor.ts +85 -0
  167. package/src/observability/service.ts +303 -0
  168. package/src/observability/trace.ts +37 -0
  169. package/src/observability/types.ts +196 -0
  170. package/src/openapi/__tests__/decorators.test.ts +335 -0
  171. package/src/openapi/__tests__/document-builder.test.ts +285 -0
  172. package/src/openapi/__tests__/route-scanner.test.ts +334 -0
  173. package/src/openapi/__tests__/schema-generator.test.ts +275 -0
  174. package/src/openapi/decorators.ts +328 -0
  175. package/src/openapi/document-builder.ts +274 -0
  176. package/src/openapi/index.ts +112 -0
  177. package/src/openapi/metadata.ts +112 -0
  178. package/src/openapi/route-scanner.ts +289 -0
  179. package/src/openapi/schema-generator.ts +256 -0
  180. package/src/openapi/swagger-module.ts +166 -0
  181. package/src/openapi/types.ts +398 -0
  182. package/src/orm/index.ts +10 -0
  183. package/src/rpc/index.ts +3 -1
  184. package/src/schema/index.ts +9 -0
  185. package/src/security/index.ts +15 -6
  186. package/src/ssg/index.ts +9 -8
  187. package/src/telemetry/index.ts +76 -22
  188. package/src/template/index.ts +7 -0
  189. package/src/templates/engine.ts +224 -0
  190. package/src/templates/index.ts +9 -0
  191. package/src/templates/loader.ts +331 -0
  192. package/src/templates/renderers/markdown.ts +212 -0
  193. package/src/templates/renderers/simple.ts +269 -0
  194. package/src/templates/types.ts +154 -0
  195. package/src/testing/index.ts +100 -27
  196. package/src/types/optional-deps.d.ts +347 -187
  197. package/src/validation/index.ts +92 -2
  198. package/src/validation/schemas.ts +536 -0
  199. package/tests/integration/fullstack.test.ts +4 -4
  200. package/tests/unit/database.test.ts +2 -72
  201. package/tests/unit/env-validation.test.ts +166 -0
  202. package/tests/unit/events.test.ts +910 -0
  203. package/tests/unit/i18n.test.ts +455 -0
  204. package/tests/unit/jobs.test.ts +493 -0
  205. package/tests/unit/notification.test.ts +988 -0
  206. package/tests/unit/observability.test.ts +453 -0
  207. package/tests/unit/orm/builder.test.ts +323 -0
  208. package/tests/unit/orm/casts.test.ts +179 -0
  209. package/tests/unit/orm/compiler.test.ts +220 -0
  210. package/tests/unit/orm/eager-loading.test.ts +285 -0
  211. package/tests/unit/orm/hooks.test.ts +191 -0
  212. package/tests/unit/orm/model.test.ts +373 -0
  213. package/tests/unit/orm/relationships.test.ts +303 -0
  214. package/tests/unit/orm/scopes.test.ts +74 -0
  215. package/tests/unit/templates-simple.test.ts +53 -0
  216. package/tests/unit/templates.test.ts +454 -0
  217. package/tests/unit/validation.test.ts +18 -24
  218. package/tsconfig.json +11 -3
@@ -0,0 +1,274 @@
1
+ /**
2
+ * OpenAPI Document Builder
3
+ *
4
+ * Fluent API for building OpenAPI 3.1 documents with configuration for
5
+ * servers, security schemes, tags, and other top-level metadata.
6
+ */
7
+
8
+ import type {
9
+ ApiKeySecurityOptions,
10
+ OpenAPIComponents,
11
+ OpenAPIDocument,
12
+ OpenAPISecurityScheme,
13
+ OpenAPIServer,
14
+ OpenAPITag,
15
+ SecuritySchemeOptions,
16
+ } from './types';
17
+
18
+ /**
19
+ * DocumentBuilder - Fluent API for constructing OpenAPI documents
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const document = new DocumentBuilder()
24
+ * .setTitle('My API')
25
+ * .setVersion('1.0.0')
26
+ * .setDescription('API description')
27
+ * .addBearerAuth()
28
+ * .addTag('users', 'User management endpoints')
29
+ * .build();
30
+ * ```
31
+ */
32
+ export class DocumentBuilder {
33
+ private document: Partial<OpenAPIDocument> = {
34
+ openapi: '3.1.0',
35
+ info: {
36
+ title: 'API',
37
+ version: '1.0.0',
38
+ },
39
+ paths: {},
40
+ components: {
41
+ schemas: {},
42
+ securitySchemes: {},
43
+ },
44
+ tags: [],
45
+ };
46
+
47
+ /**
48
+ * Set the API title
49
+ */
50
+ setTitle(title: string): this {
51
+ if (!this.document.info) {
52
+ this.document.info = { title, version: '1.0.0' };
53
+ } else {
54
+ this.document.info.title = title;
55
+ }
56
+ return this;
57
+ }
58
+
59
+ /**
60
+ * Set the API description
61
+ */
62
+ setDescription(description: string): this {
63
+ if (!this.document.info) {
64
+ this.document.info = { title: 'API', version: '1.0.0', description };
65
+ } else {
66
+ this.document.info.description = description;
67
+ }
68
+ return this;
69
+ }
70
+
71
+ /**
72
+ * Set the API version
73
+ */
74
+ setVersion(version: string): this {
75
+ if (!this.document.info) {
76
+ this.document.info = { title: 'API', version };
77
+ } else {
78
+ this.document.info.version = version;
79
+ }
80
+ return this;
81
+ }
82
+
83
+ /**
84
+ * Set contact information
85
+ */
86
+ setContact(name: string, url?: string, email?: string): this {
87
+ if (!this.document.info) {
88
+ this.document.info = { title: 'API', version: '1.0.0' };
89
+ }
90
+ this.document.info.contact = { name, url, email };
91
+ return this;
92
+ }
93
+
94
+ /**
95
+ * Set license information
96
+ */
97
+ setLicense(name: string, url?: string): this {
98
+ if (!this.document.info) {
99
+ this.document.info = { title: 'API', version: '1.0.0' };
100
+ }
101
+ this.document.info.license = { name, url };
102
+ return this;
103
+ }
104
+
105
+ /**
106
+ * Add a server
107
+ */
108
+ addServer(url: string, description?: string): this {
109
+ if (!this.document.servers) {
110
+ this.document.servers = [];
111
+ }
112
+ this.document.servers.push({ url, description });
113
+ return this;
114
+ }
115
+
116
+ /**
117
+ * Add Bearer token authentication
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * builder.addBearerAuth('JWT')
122
+ * ```
123
+ */
124
+ addBearerAuth(
125
+ name = 'bearer',
126
+ options?: SecuritySchemeOptions,
127
+ ): this {
128
+ if (!this.document.components) {
129
+ this.document.components = { schemas: {}, securitySchemes: {} };
130
+ }
131
+ if (!this.document.components.securitySchemes) {
132
+ this.document.components.securitySchemes = {};
133
+ }
134
+
135
+ const scheme: OpenAPISecurityScheme = {
136
+ type: 'http',
137
+ scheme: 'bearer',
138
+ bearerFormat: options?.bearerFormat ?? 'JWT',
139
+ };
140
+
141
+ if (options?.description) {
142
+ scheme.description = options.description;
143
+ }
144
+
145
+ this.document.components.securitySchemes[name] = scheme;
146
+ return this;
147
+ }
148
+
149
+ /**
150
+ * Add Basic authentication
151
+ */
152
+ addBasicAuth(name = 'basic', options?: SecuritySchemeOptions): this {
153
+ if (!this.document.components) {
154
+ this.document.components = { schemas: {}, securitySchemes: {} };
155
+ }
156
+ if (!this.document.components.securitySchemes) {
157
+ this.document.components.securitySchemes = {};
158
+ }
159
+
160
+ const scheme: OpenAPISecurityScheme = {
161
+ type: 'http',
162
+ scheme: 'basic',
163
+ };
164
+
165
+ if (options?.description) {
166
+ scheme.description = options.description;
167
+ }
168
+
169
+ this.document.components.securitySchemes[name] = scheme;
170
+ return this;
171
+ }
172
+
173
+ /**
174
+ * Add API Key authentication
175
+ */
176
+ addApiKey(
177
+ options: ApiKeySecurityOptions,
178
+ name = 'api_key',
179
+ ): this {
180
+ if (!this.document.components) {
181
+ this.document.components = { schemas: {}, securitySchemes: {} };
182
+ }
183
+ if (!this.document.components.securitySchemes) {
184
+ this.document.components.securitySchemes = {};
185
+ }
186
+
187
+ const scheme: OpenAPISecurityScheme = {
188
+ type: 'apiKey',
189
+ name: options.name,
190
+ in: options.in,
191
+ };
192
+
193
+ if (options.description) {
194
+ scheme.description = options.description;
195
+ }
196
+
197
+ this.document.components.securitySchemes[name] = scheme;
198
+ return this;
199
+ }
200
+
201
+ /**
202
+ * Add an OAuth2 security scheme
203
+ */
204
+ addOAuth2(
205
+ name: string,
206
+ authorizationUrl: string,
207
+ tokenUrl?: string,
208
+ refreshUrl?: string,
209
+ ): this {
210
+ if (!this.document.components) {
211
+ this.document.components = { schemas: {}, securitySchemes: {} };
212
+ }
213
+ if (!this.document.components.securitySchemes) {
214
+ this.document.components.securitySchemes = {};
215
+ }
216
+
217
+ this.document.components.securitySchemes[name] = {
218
+ type: 'oauth2',
219
+ flows: {
220
+ authorizationCode: {
221
+ authorizationUrl,
222
+ tokenUrl: tokenUrl || '',
223
+ refreshUrl,
224
+ scopes: {},
225
+ },
226
+ },
227
+ };
228
+
229
+ return this;
230
+ }
231
+
232
+ /**
233
+ * Add an OpenID Connect security scheme
234
+ */
235
+ addOpenIdConnect(name: string, url: string): this {
236
+ if (!this.document.components) {
237
+ this.document.components = { schemas: {}, securitySchemes: {} };
238
+ }
239
+ if (!this.document.components.securitySchemes) {
240
+ this.document.components.securitySchemes = {};
241
+ }
242
+
243
+ this.document.components.securitySchemes[name] = {
244
+ type: 'openIdConnect',
245
+ openIdConnectUrl: url,
246
+ };
247
+
248
+ return this;
249
+ }
250
+
251
+ /**
252
+ * Add a tag for organizing operations
253
+ */
254
+ addTag(name: string, description?: string): this {
255
+ if (!this.document.tags) {
256
+ this.document.tags = [];
257
+ }
258
+
259
+ const tag: OpenAPITag = { name };
260
+ if (description) {
261
+ tag.description = description;
262
+ }
263
+
264
+ this.document.tags.push(tag);
265
+ return this;
266
+ }
267
+
268
+ /**
269
+ * Build and return the final OpenAPI document
270
+ */
271
+ build(): OpenAPIDocument {
272
+ return this.document as OpenAPIDocument;
273
+ }
274
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * OpenAPI Module
3
+ *
4
+ * Auto-generate OpenAPI 3.1 specifications from Bueno controllers and decorators.
5
+ * Provides decorators for documenting API endpoints and a SwaggerModule for setup.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import {
10
+ * DocumentBuilder,
11
+ * SwaggerModule,
12
+ * ApiOperation,
13
+ * ApiResponse,
14
+ * ApiTags,
15
+ * } from '@buenojs/bueno/openapi';
16
+ *
17
+ * // 1. Document your controller
18
+ * @Controller('/users')
19
+ * @ApiTags('users')
20
+ * class UsersController {
21
+ * @Get()
22
+ * @ApiOperation({ summary: 'List all users' })
23
+ * @ApiResponse({ status: 200, description: 'Success', type: [User] })
24
+ * async getAll() { ... }
25
+ * }
26
+ *
27
+ * // 2. Create OpenAPI document
28
+ * const config = new DocumentBuilder()
29
+ * .setTitle('My API')
30
+ * .setVersion('1.0.0')
31
+ * .addBearerAuth()
32
+ * .build();
33
+ *
34
+ * const document = SwaggerModule.createDocument(app, config, [UsersController]);
35
+ *
36
+ * // 3. Setup Swagger UI
37
+ * SwaggerModule.setup('/api-docs', app, document);
38
+ * ```
39
+ */
40
+
41
+ // ============= Type Exports =============
42
+
43
+ export type {
44
+ OpenAPIDocument,
45
+ OpenAPIInfo,
46
+ OpenAPIContact,
47
+ OpenAPILicense,
48
+ OpenAPIServer,
49
+ OpenAPIPaths,
50
+ OpenAPIPath,
51
+ OpenAPIOperation,
52
+ OpenAPIExternalDocs,
53
+ OpenAPIParameter,
54
+ OpenAPIRequestBody,
55
+ OpenAPIMediaType,
56
+ OpenAPIExample,
57
+ OpenAPIResponse,
58
+ OpenAPIHeader,
59
+ OpenAPIResponses,
60
+ OpenAPISchema,
61
+ OpenAPIDiscriminator,
62
+ OpenAPIXML,
63
+ OpenAPIComponents,
64
+ OpenAPISecurityScheme,
65
+ OpenAPIOAuthFlows,
66
+ OpenAPIOAuthFlow,
67
+ OpenAPISecurity,
68
+ OpenAPITag,
69
+ SwaggerOptions,
70
+ ApiOperationOptions,
71
+ ApiResponseOptions,
72
+ ApiParamOptions,
73
+ ApiQueryOptions,
74
+ ApiHeaderOptions,
75
+ ApiBodyOptions,
76
+ ApiPropertyOptions,
77
+ SecuritySchemeOptions,
78
+ ApiKeySecurityOptions,
79
+ Constructor,
80
+ } from './types';
81
+
82
+ // ============= Class Exports =============
83
+
84
+ export { DocumentBuilder } from './document-builder';
85
+ export { SchemaGenerator } from './schema-generator';
86
+ export { RouteScanner } from './route-scanner';
87
+ export { SwaggerModule } from './swagger-module';
88
+
89
+ // ============= Decorator Exports =============
90
+
91
+ // Class-level decorators
92
+ export {
93
+ ApiTags,
94
+ ApiBearerAuth,
95
+ ApiBasicAuth,
96
+ ApiApiKey,
97
+ ApiExcludeController,
98
+ } from './decorators';
99
+
100
+ // Method-level decorators
101
+ export {
102
+ ApiOperation,
103
+ ApiResponse,
104
+ ApiParam,
105
+ ApiQuery,
106
+ ApiHeader,
107
+ ApiBody,
108
+ ApiExcludeEndpoint,
109
+ } from './decorators';
110
+
111
+ // Property-level decorators (for DTOs)
112
+ export { ApiProperty, ApiPropertyOptional } from './decorators';
@@ -0,0 +1,112 @@
1
+ /**
2
+ * OpenAPI Metadata Storage
3
+ *
4
+ * Isolated metadata storage using WeakMap, following the same pattern as src/modules/metadata.ts
5
+ * This avoids circular dependencies and keeps metadata separate from the core module system.
6
+ */
7
+
8
+ import type { Constructor } from './types';
9
+
10
+ // ============= Class-Level Metadata =============
11
+
12
+ /**
13
+ * Stores metadata on class constructors (e.g., @ApiTags, @ApiBearerAuth, @ApiExcludeController)
14
+ */
15
+ const classMetadataStore = new WeakMap<Constructor, Map<string, unknown>>();
16
+
17
+ /**
18
+ * Set metadata on a class constructor
19
+ */
20
+ export function setApiMetadata(
21
+ target: Constructor,
22
+ key: string,
23
+ value: unknown,
24
+ ): void {
25
+ if (!classMetadataStore.has(target)) {
26
+ classMetadataStore.set(target, new Map());
27
+ }
28
+ classMetadataStore.get(target)?.set(key, value);
29
+ }
30
+
31
+ /**
32
+ * Get metadata from a class constructor
33
+ */
34
+ export function getApiMetadata<T>(
35
+ target: Constructor,
36
+ key: string,
37
+ ): T | undefined {
38
+ return classMetadataStore.get(target)?.get(key) as T | undefined;
39
+ }
40
+
41
+ // ============= Method/Prototype-Level Metadata =============
42
+
43
+ /**
44
+ * Stores metadata on method prototypes (e.g., @ApiOperation, @ApiResponse, @ApiParam)
45
+ */
46
+ const methodMetadataStore = new WeakMap<object, Map<string, unknown>>();
47
+
48
+ /**
49
+ * Set metadata on a method prototype
50
+ */
51
+ export function setApiMethodMetadata(
52
+ target: object,
53
+ key: string,
54
+ value: unknown,
55
+ ): void {
56
+ if (!methodMetadataStore.has(target)) {
57
+ methodMetadataStore.set(target, new Map());
58
+ }
59
+ methodMetadataStore.get(target)?.set(key, value);
60
+ }
61
+
62
+ /**
63
+ * Get metadata from a method prototype
64
+ */
65
+ export function getApiMethodMetadata<T>(
66
+ target: object,
67
+ key: string,
68
+ ): T | undefined {
69
+ return methodMetadataStore.get(target)?.get(key) as T | undefined;
70
+ }
71
+
72
+ // ============= Property-Level Metadata =============
73
+
74
+ /**
75
+ * Stores metadata on class properties (e.g., @ApiProperty decorators on DTO properties)
76
+ */
77
+ const propertyMetadataStore = new WeakMap<object, Map<string, unknown>>();
78
+
79
+ /**
80
+ * Set metadata on a property of a class prototype
81
+ */
82
+ export function setApiPropertyMetadata(
83
+ target: object,
84
+ propertyKey: string | symbol,
85
+ value: unknown,
86
+ ): void {
87
+ if (!propertyMetadataStore.has(target)) {
88
+ propertyMetadataStore.set(target, new Map());
89
+ }
90
+ const key = typeof propertyKey === 'symbol' ? propertyKey.toString() : propertyKey;
91
+ propertyMetadataStore.get(target)?.set(key, value);
92
+ }
93
+
94
+ /**
95
+ * Get metadata from a property of a class prototype
96
+ */
97
+ export function getApiPropertyMetadata<T>(
98
+ target: object,
99
+ propertyKey: string | symbol,
100
+ ): T | undefined {
101
+ const key = typeof propertyKey === 'symbol' ? propertyKey.toString() : propertyKey;
102
+ return propertyMetadataStore.get(target)?.get(key) as T | undefined;
103
+ }
104
+
105
+ /**
106
+ * Get all property metadata keys from a class prototype
107
+ */
108
+ export function getApiPropertyKeys(target: object): (string | symbol)[] {
109
+ const metaMap = propertyMetadataStore.get(target);
110
+ if (!metaMap) return [];
111
+ return Array.from(metaMap.keys()) as (string | symbol)[];
112
+ }