@buenojs/bueno 0.8.4 → 0.8.6

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 (234) hide show
  1. package/README.md +264 -17
  2. package/dist/cli/{index.js → bin.js} +413 -332
  3. package/dist/container/index.js +273 -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/graphql/index.js +2156 -0
  8. package/dist/health/index.js +364 -0
  9. package/dist/i18n/index.js +345 -0
  10. package/dist/index.js +9694 -5047
  11. package/dist/jobs/index.js +819 -0
  12. package/dist/lock/index.js +367 -0
  13. package/dist/logger/index.js +281 -0
  14. package/dist/metrics/index.js +289 -0
  15. package/dist/middleware/index.js +77 -0
  16. package/dist/migrations/index.js +571 -0
  17. package/dist/modules/index.js +3411 -0
  18. package/dist/notification/index.js +484 -0
  19. package/dist/observability/index.js +331 -0
  20. package/dist/openapi/index.js +795 -0
  21. package/dist/orm/index.js +1356 -0
  22. package/dist/router/index.js +886 -0
  23. package/dist/rpc/index.js +691 -0
  24. package/dist/schema/index.js +400 -0
  25. package/dist/telemetry/index.js +595 -0
  26. package/dist/template/index.js +640 -0
  27. package/dist/templates/index.js +640 -0
  28. package/dist/testing/index.js +1111 -0
  29. package/dist/types/index.js +60 -0
  30. package/llms.txt +231 -0
  31. package/package.json +125 -27
  32. package/src/cache/index.ts +2 -1
  33. package/src/cli/ARCHITECTURE.md +3 -3
  34. package/src/cli/bin.ts +2 -2
  35. package/src/cli/commands/build.ts +183 -165
  36. package/src/cli/commands/dev.ts +96 -89
  37. package/src/cli/commands/generate.ts +142 -111
  38. package/src/cli/commands/help.ts +20 -16
  39. package/src/cli/commands/index.ts +3 -6
  40. package/src/cli/commands/migration.ts +124 -105
  41. package/src/cli/commands/new.ts +294 -232
  42. package/src/cli/commands/start.ts +81 -79
  43. package/src/cli/core/args.ts +68 -50
  44. package/src/cli/core/console.ts +89 -95
  45. package/src/cli/core/index.ts +4 -4
  46. package/src/cli/core/prompt.ts +65 -62
  47. package/src/cli/core/spinner.ts +23 -20
  48. package/src/cli/index.ts +46 -38
  49. package/src/cli/templates/database/index.ts +37 -18
  50. package/src/cli/templates/database/mysql.ts +3 -3
  51. package/src/cli/templates/database/none.ts +2 -2
  52. package/src/cli/templates/database/postgresql.ts +3 -3
  53. package/src/cli/templates/database/sqlite.ts +3 -3
  54. package/src/cli/templates/deploy.ts +29 -26
  55. package/src/cli/templates/docker.ts +41 -30
  56. package/src/cli/templates/frontend/index.ts +33 -15
  57. package/src/cli/templates/frontend/none.ts +2 -2
  58. package/src/cli/templates/frontend/react.ts +18 -18
  59. package/src/cli/templates/frontend/solid.ts +15 -15
  60. package/src/cli/templates/frontend/svelte.ts +17 -17
  61. package/src/cli/templates/frontend/vue.ts +15 -15
  62. package/src/cli/templates/generators/index.ts +29 -29
  63. package/src/cli/templates/generators/types.ts +21 -21
  64. package/src/cli/templates/index.ts +6 -6
  65. package/src/cli/templates/project/api.ts +37 -36
  66. package/src/cli/templates/project/default.ts +25 -25
  67. package/src/cli/templates/project/fullstack.ts +28 -26
  68. package/src/cli/templates/project/index.ts +55 -16
  69. package/src/cli/templates/project/minimal.ts +17 -12
  70. package/src/cli/templates/project/types.ts +10 -5
  71. package/src/cli/templates/project/website.ts +15 -15
  72. package/src/cli/utils/fs.ts +55 -41
  73. package/src/cli/utils/index.ts +3 -3
  74. package/src/cli/utils/strings.ts +47 -33
  75. package/src/cli/utils/version.ts +14 -8
  76. package/src/config/env-validation.ts +100 -0
  77. package/src/config/env.ts +169 -41
  78. package/src/config/index.ts +28 -20
  79. package/src/config/loader.ts +25 -16
  80. package/src/config/merge.ts +21 -10
  81. package/src/config/types.ts +566 -25
  82. package/src/config/validation.ts +215 -7
  83. package/src/container/forward-ref.ts +22 -22
  84. package/src/container/index.ts +34 -12
  85. package/src/context/index.ts +11 -1
  86. package/src/database/index.ts +7 -190
  87. package/src/database/orm/builder.ts +457 -0
  88. package/src/database/orm/casts/index.ts +130 -0
  89. package/src/database/orm/casts/types.ts +25 -0
  90. package/src/database/orm/compiler.ts +304 -0
  91. package/src/database/orm/hooks/index.ts +114 -0
  92. package/src/database/orm/index.ts +61 -0
  93. package/src/database/orm/model-registry.ts +59 -0
  94. package/src/database/orm/model.ts +821 -0
  95. package/src/database/orm/relationships/base.ts +146 -0
  96. package/src/database/orm/relationships/belongs-to-many.ts +179 -0
  97. package/src/database/orm/relationships/belongs-to.ts +56 -0
  98. package/src/database/orm/relationships/has-many.ts +45 -0
  99. package/src/database/orm/relationships/has-one.ts +41 -0
  100. package/src/database/orm/relationships/index.ts +11 -0
  101. package/src/database/orm/scopes/index.ts +55 -0
  102. package/src/events/__tests__/event-system.test.ts +235 -0
  103. package/src/events/config.ts +238 -0
  104. package/src/events/example-usage.ts +185 -0
  105. package/src/events/index.ts +278 -0
  106. package/src/events/manager.ts +385 -0
  107. package/src/events/registry.ts +182 -0
  108. package/src/events/types.ts +124 -0
  109. package/src/frontend/api-routes.ts +65 -23
  110. package/src/frontend/bundler.ts +76 -34
  111. package/src/frontend/console-client.ts +2 -2
  112. package/src/frontend/console-stream.ts +94 -38
  113. package/src/frontend/dev-server.ts +94 -46
  114. package/src/frontend/file-router.ts +61 -19
  115. package/src/frontend/frameworks/index.ts +37 -10
  116. package/src/frontend/frameworks/react.ts +10 -8
  117. package/src/frontend/frameworks/solid.ts +11 -9
  118. package/src/frontend/frameworks/svelte.ts +15 -9
  119. package/src/frontend/frameworks/vue.ts +13 -11
  120. package/src/frontend/hmr-client.ts +12 -10
  121. package/src/frontend/hmr.ts +146 -103
  122. package/src/frontend/index.ts +14 -5
  123. package/src/frontend/islands.ts +41 -22
  124. package/src/frontend/isr.ts +59 -37
  125. package/src/frontend/layout.ts +36 -21
  126. package/src/frontend/ssr/react.ts +74 -27
  127. package/src/frontend/ssr/solid.ts +54 -20
  128. package/src/frontend/ssr/svelte.ts +48 -14
  129. package/src/frontend/ssr/vue.ts +50 -18
  130. package/src/frontend/ssr.ts +83 -39
  131. package/src/frontend/types.ts +91 -56
  132. package/src/graphql/built-in-engine.ts +598 -0
  133. package/src/graphql/context-builder.ts +110 -0
  134. package/src/graphql/decorators.ts +358 -0
  135. package/src/graphql/execution-pipeline.ts +227 -0
  136. package/src/graphql/graphql-module.ts +563 -0
  137. package/src/graphql/index.ts +101 -0
  138. package/src/graphql/metadata.ts +237 -0
  139. package/src/graphql/schema-builder.ts +319 -0
  140. package/src/graphql/subscription-handler.ts +283 -0
  141. package/src/graphql/types.ts +324 -0
  142. package/src/health/index.ts +21 -9
  143. package/src/i18n/engine.ts +305 -0
  144. package/src/i18n/index.ts +38 -0
  145. package/src/i18n/loader.ts +218 -0
  146. package/src/i18n/middleware.ts +164 -0
  147. package/src/i18n/negotiator.ts +162 -0
  148. package/src/i18n/types.ts +158 -0
  149. package/src/index.ts +182 -27
  150. package/src/jobs/drivers/memory.ts +315 -0
  151. package/src/jobs/drivers/redis.ts +459 -0
  152. package/src/jobs/index.ts +30 -0
  153. package/src/jobs/queue.ts +281 -0
  154. package/src/jobs/types.ts +295 -0
  155. package/src/jobs/worker.ts +380 -0
  156. package/src/logger/index.ts +1 -3
  157. package/src/logger/transports/index.ts +62 -22
  158. package/src/metrics/index.ts +25 -16
  159. package/src/migrations/index.ts +9 -0
  160. package/src/modules/filters.ts +13 -17
  161. package/src/modules/guards.ts +49 -26
  162. package/src/modules/index.ts +457 -299
  163. package/src/modules/interceptors.ts +58 -20
  164. package/src/modules/lazy.ts +11 -19
  165. package/src/modules/lifecycle.ts +15 -7
  166. package/src/modules/metadata.ts +15 -5
  167. package/src/modules/pipes.ts +94 -72
  168. package/src/notification/channels/base.ts +68 -0
  169. package/src/notification/channels/email.ts +105 -0
  170. package/src/notification/channels/push.ts +104 -0
  171. package/src/notification/channels/sms.ts +105 -0
  172. package/src/notification/channels/whatsapp.ts +104 -0
  173. package/src/notification/index.ts +48 -0
  174. package/src/notification/service.ts +354 -0
  175. package/src/notification/types.ts +344 -0
  176. package/src/observability/__tests__/observability.test.ts +483 -0
  177. package/src/observability/breadcrumbs.ts +114 -0
  178. package/src/observability/index.ts +136 -0
  179. package/src/observability/interceptor.ts +85 -0
  180. package/src/observability/service.ts +303 -0
  181. package/src/observability/trace.ts +37 -0
  182. package/src/observability/types.ts +196 -0
  183. package/src/openapi/__tests__/decorators.test.ts +335 -0
  184. package/src/openapi/__tests__/document-builder.test.ts +285 -0
  185. package/src/openapi/__tests__/route-scanner.test.ts +334 -0
  186. package/src/openapi/__tests__/schema-generator.test.ts +275 -0
  187. package/src/openapi/decorators.ts +328 -0
  188. package/src/openapi/document-builder.ts +274 -0
  189. package/src/openapi/index.ts +112 -0
  190. package/src/openapi/metadata.ts +112 -0
  191. package/src/openapi/route-scanner.ts +289 -0
  192. package/src/openapi/schema-generator.ts +256 -0
  193. package/src/openapi/swagger-module.ts +166 -0
  194. package/src/openapi/types.ts +398 -0
  195. package/src/orm/index.ts +10 -0
  196. package/src/rpc/index.ts +3 -1
  197. package/src/schema/index.ts +9 -0
  198. package/src/security/index.ts +15 -6
  199. package/src/ssg/index.ts +9 -8
  200. package/src/telemetry/index.ts +76 -22
  201. package/src/template/index.ts +7 -0
  202. package/src/templates/engine.ts +224 -0
  203. package/src/templates/index.ts +9 -0
  204. package/src/templates/loader.ts +331 -0
  205. package/src/templates/renderers/markdown.ts +212 -0
  206. package/src/templates/renderers/simple.ts +269 -0
  207. package/src/templates/types.ts +154 -0
  208. package/src/testing/index.ts +100 -27
  209. package/src/types/optional-deps.d.ts +347 -187
  210. package/src/validation/index.ts +92 -2
  211. package/src/validation/schemas.ts +536 -0
  212. package/tests/integration/cli.test.ts +19 -19
  213. package/tests/integration/fullstack.test.ts +4 -4
  214. package/tests/unit/cli.test.ts +1 -1
  215. package/tests/unit/database.test.ts +2 -72
  216. package/tests/unit/env-validation.test.ts +166 -0
  217. package/tests/unit/events.test.ts +910 -0
  218. package/tests/unit/graphql.test.ts +991 -0
  219. package/tests/unit/i18n.test.ts +455 -0
  220. package/tests/unit/jobs.test.ts +493 -0
  221. package/tests/unit/notification.test.ts +988 -0
  222. package/tests/unit/observability.test.ts +453 -0
  223. package/tests/unit/orm/builder.test.ts +323 -0
  224. package/tests/unit/orm/casts.test.ts +179 -0
  225. package/tests/unit/orm/compiler.test.ts +220 -0
  226. package/tests/unit/orm/eager-loading.test.ts +285 -0
  227. package/tests/unit/orm/hooks.test.ts +191 -0
  228. package/tests/unit/orm/model.test.ts +373 -0
  229. package/tests/unit/orm/relationships.test.ts +303 -0
  230. package/tests/unit/orm/scopes.test.ts +74 -0
  231. package/tests/unit/templates-simple.test.ts +53 -0
  232. package/tests/unit/templates.test.ts +454 -0
  233. package/tests/unit/validation.test.ts +18 -24
  234. package/tsconfig.json +11 -3
@@ -0,0 +1,795 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
13
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
15
+ r = Reflect.decorate(decorators, target, key, desc);
16
+ else
17
+ for (var i = decorators.length - 1;i >= 0; i--)
18
+ if (d = decorators[i])
19
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
21
+ };
22
+ var __legacyMetadataTS = (k, v) => {
23
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
24
+ return Reflect.metadata(k, v);
25
+ };
26
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
27
+ var __require = import.meta.require;
28
+
29
+ // src/openapi/metadata.ts
30
+ var exports_metadata = {};
31
+ __export(exports_metadata, {
32
+ setApiPropertyMetadata: () => setApiPropertyMetadata,
33
+ setApiMethodMetadata: () => setApiMethodMetadata,
34
+ setApiMetadata: () => setApiMetadata,
35
+ getApiPropertyMetadata: () => getApiPropertyMetadata,
36
+ getApiPropertyKeys: () => getApiPropertyKeys,
37
+ getApiMethodMetadata: () => getApiMethodMetadata,
38
+ getApiMetadata: () => getApiMetadata
39
+ });
40
+ function setApiMetadata(target, key, value) {
41
+ if (!classMetadataStore.has(target)) {
42
+ classMetadataStore.set(target, new Map);
43
+ }
44
+ classMetadataStore.get(target)?.set(key, value);
45
+ }
46
+ function getApiMetadata(target, key) {
47
+ return classMetadataStore.get(target)?.get(key);
48
+ }
49
+ function setApiMethodMetadata(target, key, value) {
50
+ if (!methodMetadataStore.has(target)) {
51
+ methodMetadataStore.set(target, new Map);
52
+ }
53
+ methodMetadataStore.get(target)?.set(key, value);
54
+ }
55
+ function getApiMethodMetadata(target, key) {
56
+ return methodMetadataStore.get(target)?.get(key);
57
+ }
58
+ function setApiPropertyMetadata(target, propertyKey, value) {
59
+ if (!propertyMetadataStore.has(target)) {
60
+ propertyMetadataStore.set(target, new Map);
61
+ }
62
+ const key = typeof propertyKey === "symbol" ? propertyKey.toString() : propertyKey;
63
+ propertyMetadataStore.get(target)?.set(key, value);
64
+ }
65
+ function getApiPropertyMetadata(target, propertyKey) {
66
+ const key = typeof propertyKey === "symbol" ? propertyKey.toString() : propertyKey;
67
+ return propertyMetadataStore.get(target)?.get(key);
68
+ }
69
+ function getApiPropertyKeys(target) {
70
+ const metaMap = propertyMetadataStore.get(target);
71
+ if (!metaMap)
72
+ return [];
73
+ return Array.from(metaMap.keys());
74
+ }
75
+ var classMetadataStore, methodMetadataStore, propertyMetadataStore;
76
+ var init_metadata = __esm(() => {
77
+ classMetadataStore = new WeakMap;
78
+ methodMetadataStore = new WeakMap;
79
+ propertyMetadataStore = new WeakMap;
80
+ });
81
+
82
+ // src/openapi/document-builder.ts
83
+ class DocumentBuilder {
84
+ document = {
85
+ openapi: "3.1.0",
86
+ info: {
87
+ title: "API",
88
+ version: "1.0.0"
89
+ },
90
+ paths: {},
91
+ components: {
92
+ schemas: {},
93
+ securitySchemes: {}
94
+ },
95
+ tags: []
96
+ };
97
+ setTitle(title) {
98
+ if (!this.document.info) {
99
+ this.document.info = { title, version: "1.0.0" };
100
+ } else {
101
+ this.document.info.title = title;
102
+ }
103
+ return this;
104
+ }
105
+ setDescription(description) {
106
+ if (!this.document.info) {
107
+ this.document.info = { title: "API", version: "1.0.0", description };
108
+ } else {
109
+ this.document.info.description = description;
110
+ }
111
+ return this;
112
+ }
113
+ setVersion(version) {
114
+ if (!this.document.info) {
115
+ this.document.info = { title: "API", version };
116
+ } else {
117
+ this.document.info.version = version;
118
+ }
119
+ return this;
120
+ }
121
+ setContact(name, url, email) {
122
+ if (!this.document.info) {
123
+ this.document.info = { title: "API", version: "1.0.0" };
124
+ }
125
+ this.document.info.contact = { name, url, email };
126
+ return this;
127
+ }
128
+ setLicense(name, url) {
129
+ if (!this.document.info) {
130
+ this.document.info = { title: "API", version: "1.0.0" };
131
+ }
132
+ this.document.info.license = { name, url };
133
+ return this;
134
+ }
135
+ addServer(url, description) {
136
+ if (!this.document.servers) {
137
+ this.document.servers = [];
138
+ }
139
+ this.document.servers.push({ url, description });
140
+ return this;
141
+ }
142
+ addBearerAuth(name = "bearer", options) {
143
+ if (!this.document.components) {
144
+ this.document.components = { schemas: {}, securitySchemes: {} };
145
+ }
146
+ if (!this.document.components.securitySchemes) {
147
+ this.document.components.securitySchemes = {};
148
+ }
149
+ const scheme = {
150
+ type: "http",
151
+ scheme: "bearer",
152
+ bearerFormat: options?.bearerFormat ?? "JWT"
153
+ };
154
+ if (options?.description) {
155
+ scheme.description = options.description;
156
+ }
157
+ this.document.components.securitySchemes[name] = scheme;
158
+ return this;
159
+ }
160
+ addBasicAuth(name = "basic", options) {
161
+ if (!this.document.components) {
162
+ this.document.components = { schemas: {}, securitySchemes: {} };
163
+ }
164
+ if (!this.document.components.securitySchemes) {
165
+ this.document.components.securitySchemes = {};
166
+ }
167
+ const scheme = {
168
+ type: "http",
169
+ scheme: "basic"
170
+ };
171
+ if (options?.description) {
172
+ scheme.description = options.description;
173
+ }
174
+ this.document.components.securitySchemes[name] = scheme;
175
+ return this;
176
+ }
177
+ addApiKey(options, name = "api_key") {
178
+ if (!this.document.components) {
179
+ this.document.components = { schemas: {}, securitySchemes: {} };
180
+ }
181
+ if (!this.document.components.securitySchemes) {
182
+ this.document.components.securitySchemes = {};
183
+ }
184
+ const scheme = {
185
+ type: "apiKey",
186
+ name: options.name,
187
+ in: options.in
188
+ };
189
+ if (options.description) {
190
+ scheme.description = options.description;
191
+ }
192
+ this.document.components.securitySchemes[name] = scheme;
193
+ return this;
194
+ }
195
+ addOAuth2(name, authorizationUrl, tokenUrl, refreshUrl) {
196
+ if (!this.document.components) {
197
+ this.document.components = { schemas: {}, securitySchemes: {} };
198
+ }
199
+ if (!this.document.components.securitySchemes) {
200
+ this.document.components.securitySchemes = {};
201
+ }
202
+ this.document.components.securitySchemes[name] = {
203
+ type: "oauth2",
204
+ flows: {
205
+ authorizationCode: {
206
+ authorizationUrl,
207
+ tokenUrl: tokenUrl || "",
208
+ refreshUrl,
209
+ scopes: {}
210
+ }
211
+ }
212
+ };
213
+ return this;
214
+ }
215
+ addOpenIdConnect(name, url) {
216
+ if (!this.document.components) {
217
+ this.document.components = { schemas: {}, securitySchemes: {} };
218
+ }
219
+ if (!this.document.components.securitySchemes) {
220
+ this.document.components.securitySchemes = {};
221
+ }
222
+ this.document.components.securitySchemes[name] = {
223
+ type: "openIdConnect",
224
+ openIdConnectUrl: url
225
+ };
226
+ return this;
227
+ }
228
+ addTag(name, description) {
229
+ if (!this.document.tags) {
230
+ this.document.tags = [];
231
+ }
232
+ const tag = { name };
233
+ if (description) {
234
+ tag.description = description;
235
+ }
236
+ this.document.tags.push(tag);
237
+ return this;
238
+ }
239
+ build() {
240
+ return this.document;
241
+ }
242
+ }
243
+ // src/openapi/schema-generator.ts
244
+ init_metadata();
245
+
246
+ class SchemaGenerator {
247
+ schemas = new Map;
248
+ typeNames = new Map;
249
+ typeCounter = 0;
250
+ generateSchema(type) {
251
+ if (typeof type === "string") {
252
+ return this.generatePrimitiveSchema(type);
253
+ }
254
+ if (typeof type === "function") {
255
+ const typeName = this.getTypeName(type);
256
+ if (this.schemas.has(typeName)) {
257
+ return { $ref: `#/components/schemas/${typeName}` };
258
+ }
259
+ if (this.isBuiltInType(type)) {
260
+ return this.generatePrimitiveSchema(type);
261
+ }
262
+ if (type === Array) {
263
+ return { type: "array", items: { type: "object" } };
264
+ }
265
+ return this.generateObjectSchema(type);
266
+ }
267
+ return { type: "object" };
268
+ }
269
+ generateObjectSchema(type) {
270
+ const typeName = this.getTypeName(type);
271
+ const properties = {};
272
+ const required = [];
273
+ const propertyKeys = getApiPropertyKeys(type.prototype);
274
+ for (const key of propertyKeys) {
275
+ const propName = typeof key === "symbol" ? key.toString() : key;
276
+ const propOptions = getApiPropertyMetadata(type.prototype, key);
277
+ if (propOptions) {
278
+ properties[propName] = this.generatePropertySchema(propOptions);
279
+ if (propOptions.required !== false) {
280
+ required.push(propName);
281
+ }
282
+ }
283
+ }
284
+ const schema = {
285
+ type: "object",
286
+ properties: Object.keys(properties).length > 0 ? properties : undefined,
287
+ required: required.length > 0 ? required : undefined
288
+ };
289
+ this.schemas.set(typeName, schema);
290
+ return { $ref: `#/components/schemas/${typeName}` };
291
+ }
292
+ generatePropertySchema(options) {
293
+ const schema = {};
294
+ if (options.type) {
295
+ if (typeof options.type === "string") {
296
+ const typeSchema = this.mapStringType(options.type);
297
+ Object.assign(schema, typeSchema);
298
+ } else if (typeof options.type === "function") {
299
+ const nested = this.generateSchema(options.type);
300
+ Object.assign(schema, nested);
301
+ }
302
+ }
303
+ if (options.minLength !== undefined)
304
+ schema.minLength = options.minLength;
305
+ if (options.maxLength !== undefined)
306
+ schema.maxLength = options.maxLength;
307
+ if (options.pattern !== undefined)
308
+ schema.pattern = options.pattern;
309
+ if (options.minimum !== undefined)
310
+ schema.minimum = options.minimum;
311
+ if (options.maximum !== undefined)
312
+ schema.maximum = options.maximum;
313
+ if (options.minItems !== undefined)
314
+ schema.minItems = options.minItems;
315
+ if (options.maxItems !== undefined)
316
+ schema.maxItems = options.maxItems;
317
+ if (options.items !== undefined)
318
+ schema.items = options.items;
319
+ if (options.enum !== undefined) {
320
+ schema.enum = options.enum;
321
+ }
322
+ if (options.format !== undefined)
323
+ schema.format = options.format;
324
+ if (options.title !== undefined)
325
+ schema.title = options.title;
326
+ if (options.description !== undefined)
327
+ schema.description = options.description;
328
+ if (options.example !== undefined)
329
+ schema.example = options.example;
330
+ if (options.default !== undefined)
331
+ schema.default = options.default;
332
+ if (options.nullable !== undefined)
333
+ schema.nullable = options.nullable;
334
+ if (options.readOnly !== undefined)
335
+ schema.readOnly = options.readOnly;
336
+ if (options.writeOnly !== undefined)
337
+ schema.writeOnly = options.writeOnly;
338
+ return schema;
339
+ }
340
+ generatePrimitiveSchema(type) {
341
+ if (typeof type === "string") {
342
+ return this.mapStringType(type);
343
+ }
344
+ if (type === String)
345
+ return { type: "string" };
346
+ if (type === Number)
347
+ return { type: "number" };
348
+ if (type === Boolean)
349
+ return { type: "boolean" };
350
+ if (type === Date)
351
+ return { type: "string", format: "date-time" };
352
+ if (type === Array)
353
+ return { type: "array", items: {} };
354
+ return { type: "object" };
355
+ }
356
+ mapStringType(type) {
357
+ switch (type.toLowerCase()) {
358
+ case "string":
359
+ return { type: "string" };
360
+ case "number":
361
+ return { type: "number" };
362
+ case "integer":
363
+ return { type: "integer" };
364
+ case "boolean":
365
+ return { type: "boolean" };
366
+ case "date":
367
+ return { type: "string", format: "date" };
368
+ case "datetime":
369
+ case "date-time":
370
+ return { type: "string", format: "date-time" };
371
+ case "email":
372
+ return { type: "string", format: "email" };
373
+ case "uuid":
374
+ return { type: "string", format: "uuid" };
375
+ case "url":
376
+ case "uri":
377
+ return { type: "string", format: "uri" };
378
+ case "object":
379
+ return { type: "object" };
380
+ case "array":
381
+ return { type: "array", items: {} };
382
+ default:
383
+ return { type: "string" };
384
+ }
385
+ }
386
+ isBuiltInType(type) {
387
+ return type === String || type === Number || type === Boolean || type === Date || type === Array || type === Object;
388
+ }
389
+ getTypeName(type) {
390
+ if (this.typeNames.has(type)) {
391
+ return this.typeNames.get(type);
392
+ }
393
+ let name = type.name;
394
+ if (!name || name === "Object" || name === "Function") {
395
+ name = `Schema_${++this.typeCounter}`;
396
+ }
397
+ this.typeNames.set(type, name);
398
+ return name;
399
+ }
400
+ getSchemas() {
401
+ const result = {};
402
+ for (const [name, schema] of this.schemas) {
403
+ result[name] = schema;
404
+ }
405
+ return result;
406
+ }
407
+ clear() {
408
+ this.schemas.clear();
409
+ this.typeNames.clear();
410
+ this.typeCounter = 0;
411
+ }
412
+ }
413
+ // src/openapi/route-scanner.ts
414
+ init_metadata();
415
+
416
+ // src/modules/metadata.ts
417
+ var metadataStore = new WeakMap;
418
+ function setMetadata(target, key, value) {
419
+ if (!metadataStore.has(target)) {
420
+ metadataStore.set(target, new Map);
421
+ }
422
+ metadataStore.get(target)?.set(key, value);
423
+ }
424
+ function getMetadata(target, key) {
425
+ return metadataStore.get(target)?.get(key);
426
+ }
427
+ var prototypeMetadataStore = new WeakMap;
428
+ function setPrototypeMetadata(target, key, value) {
429
+ if (!prototypeMetadataStore.has(target)) {
430
+ prototypeMetadataStore.set(target, new Map);
431
+ }
432
+ prototypeMetadataStore.get(target)?.set(key, value);
433
+ }
434
+ function getPrototypeMetadata(target, key) {
435
+ return prototypeMetadataStore.get(target)?.get(key);
436
+ }
437
+ function Injectable() {
438
+ return (target) => {
439
+ setMetadata(target, "injectable", true);
440
+ return target;
441
+ };
442
+ }
443
+ function Controller(path = "") {
444
+ return (target) => {
445
+ setMetadata(target, "controller", true);
446
+ setMetadata(target, "path", path);
447
+ return target;
448
+ };
449
+ }
450
+ function Module(metadata) {
451
+ return (target) => {
452
+ setMetadata(target, "module", metadata);
453
+ return target;
454
+ };
455
+ }
456
+
457
+ // src/openapi/route-scanner.ts
458
+ class RouteScanner {
459
+ schemaGenerator;
460
+ constructor(schemaGenerator) {
461
+ this.schemaGenerator = schemaGenerator;
462
+ }
463
+ scanControllers(controllers) {
464
+ const paths = {};
465
+ for (const controller of controllers) {
466
+ if (getApiMetadata(controller, "api:exclude")) {
467
+ continue;
468
+ }
469
+ const basePath = getMetadata(controller, "path") ?? "";
470
+ const routes = getPrototypeMetadata(controller.prototype, "routes") ?? [];
471
+ const classLevelTags = getApiMetadata(controller, "api:tags") ?? [];
472
+ const classLevelSecurity = getApiMetadata(controller, "api:security") ?? [];
473
+ for (const route of routes) {
474
+ const prototype = controller.prototype;
475
+ const handlerKey = route.handler;
476
+ if (getApiMethodMetadata(prototype, `api:exclude:${String(handlerKey)}`)) {
477
+ continue;
478
+ }
479
+ const fullPath = this.convertPathToOpenAPI(basePath + route.path);
480
+ if (!paths[fullPath]) {
481
+ paths[fullPath] = {};
482
+ }
483
+ const operation = this.generateOperation(controller, route, classLevelTags, classLevelSecurity, basePath);
484
+ paths[fullPath][route.method.toLowerCase()] = operation;
485
+ }
486
+ }
487
+ return paths;
488
+ }
489
+ generateOperation(controller, route, classLevelTags, classLevelSecurity, basePath) {
490
+ const prototype = controller.prototype;
491
+ const handlerKey = String(route.handler);
492
+ const getMethodMeta = (key) => getApiMethodMetadata(prototype, `${key}:${handlerKey}`);
493
+ const operationMeta = getMethodMeta("api:operation");
494
+ const responseMeta = getMethodMeta("api:responses") ?? [];
495
+ const paramMeta = getMethodMeta("api:params") ?? [];
496
+ const queryMeta = getMethodMeta("api:query") ?? [];
497
+ const headerMeta = getMethodMeta("api:headers") ?? [];
498
+ const bodyMeta = getMethodMeta("api:body");
499
+ const methodLevelTags = getMethodMeta("api:tags") ?? [];
500
+ const methodLevelSecurity = getMethodMeta("api:security") ?? [];
501
+ const parameters = [
502
+ ...paramMeta.map((p) => ({
503
+ name: p.name,
504
+ in: "path",
505
+ description: p.description,
506
+ required: p.required ?? true,
507
+ example: p.example,
508
+ schema: p.schema
509
+ })),
510
+ ...queryMeta.map((q) => ({
511
+ name: q.name,
512
+ in: "query",
513
+ description: q.description,
514
+ required: q.required ?? false,
515
+ example: q.example,
516
+ schema: q.schema
517
+ })),
518
+ ...headerMeta.map((h) => ({
519
+ name: h.name,
520
+ in: "header",
521
+ description: h.description,
522
+ required: h.required,
523
+ schema: h.schema
524
+ }))
525
+ ];
526
+ const responses = {};
527
+ for (const resp of responseMeta) {
528
+ const statusCode = String(resp.status);
529
+ const response = { description: resp.description };
530
+ if (resp.type || resp.schema) {
531
+ let schema = resp.schema ?? {};
532
+ if (resp.type) {
533
+ if (Array.isArray(resp.type)) {
534
+ const itemSchema = this.schemaGenerator.generateSchema(resp.type[0]);
535
+ schema = { type: "array", items: itemSchema };
536
+ } else {
537
+ schema = this.schemaGenerator.generateSchema(resp.type);
538
+ }
539
+ }
540
+ const mediaType = { schema };
541
+ response.content = { "application/json": mediaType };
542
+ }
543
+ responses[statusCode] = response;
544
+ }
545
+ if (Object.keys(responses).length === 0) {
546
+ responses["200"] = { description: "Success" };
547
+ }
548
+ const requestBody = bodyMeta ? {
549
+ description: bodyMeta.description,
550
+ required: bodyMeta.required ?? true,
551
+ content: {
552
+ "application/json": {
553
+ schema: bodyMeta.schema ?? (bodyMeta.type ? this.schemaGenerator.generateSchema(bodyMeta.type) : { type: "object" })
554
+ }
555
+ }
556
+ } : undefined;
557
+ const tags = [...new Set([...classLevelTags, ...methodLevelTags])];
558
+ const security = [...classLevelSecurity, ...methodLevelSecurity];
559
+ const operation = {
560
+ operationId: operationMeta?.operationId ?? `${route.method.toLowerCase()}_${basePath.replace(/\//g, "_")}_${handlerKey}`,
561
+ summary: operationMeta?.summary,
562
+ description: operationMeta?.description,
563
+ tags: tags.length > 0 ? tags : undefined,
564
+ parameters: parameters.length > 0 ? parameters : undefined,
565
+ requestBody,
566
+ responses,
567
+ deprecated: operationMeta?.deprecated,
568
+ security: security.length > 0 ? security : undefined
569
+ };
570
+ return operation;
571
+ }
572
+ convertPathToOpenAPI(pattern) {
573
+ return pattern.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)\??(?:<[^>]+>)?/g, "{$1}");
574
+ }
575
+ getSchemaGenerator() {
576
+ return this.schemaGenerator;
577
+ }
578
+ }
579
+ // src/openapi/swagger-module.ts
580
+ class SwaggerModule {
581
+ static createDocument(app, config, controllers) {
582
+ const schemaGenerator = new SchemaGenerator;
583
+ const scanner = new RouteScanner(schemaGenerator);
584
+ const paths = scanner.scanControllers(controllers);
585
+ const schemas = schemaGenerator.getSchemas();
586
+ return {
587
+ ...config,
588
+ paths: {
589
+ ...config.paths,
590
+ ...paths
591
+ },
592
+ components: {
593
+ ...config.components,
594
+ schemas: {
595
+ ...config.components?.schemas ?? {},
596
+ ...schemas
597
+ }
598
+ }
599
+ };
600
+ }
601
+ static setup(path, app, document, options) {
602
+ app.router.get(`${path}-json`, (ctx) => {
603
+ return ctx.json(document);
604
+ });
605
+ app.router.get(path, (ctx) => {
606
+ const html = this.generateSwaggerUI(path, document, options);
607
+ return ctx.html(html);
608
+ });
609
+ }
610
+ static generateSwaggerUI(jsonPath, document, options) {
611
+ const title = options?.title ?? "API Documentation";
612
+ const customCss = options?.customCss ?? "";
613
+ const customSiteTitle = options?.customSiteTitle ?? title;
614
+ const favicon = options?.customfavIcon ?? "";
615
+ return `<!DOCTYPE html>
616
+ <html lang="en">
617
+ <head>
618
+ <meta charset="UTF-8">
619
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
620
+ <title>${customSiteTitle}</title>
621
+ <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
622
+ <style>
623
+ html {
624
+ box-sizing: border-box;
625
+ overflow: -moz-scrollbars-vertical;
626
+ overflow-y: scroll;
627
+ }
628
+ *, *:before, *:after {
629
+ box-sizing: inherit;
630
+ }
631
+ body {
632
+ margin: 0;
633
+ padding: 0;
634
+ font-family: sans-serif;
635
+ }
636
+ ${customCss}
637
+ </style>
638
+ ${favicon ? `<link rel="icon" href="${favicon}">` : ""}
639
+ </head>
640
+ <body>
641
+ <div id="swagger-ui"></div>
642
+ <script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
643
+ <script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-standalone-preset.js"></script>
644
+ <script>
645
+ window.onload = function() {
646
+ SwaggerUIBundle({
647
+ url: '${jsonPath}-json',
648
+ dom_id: '#swagger-ui',
649
+ deepLinking: true,
650
+ presets: [
651
+ SwaggerUIBundle.presets.apis,
652
+ SwaggerUIStandalonePreset
653
+ ],
654
+ plugins: [
655
+ SwaggerUIBundle.plugins.DownloadUrl
656
+ ],
657
+ layout: 'StandaloneLayout',
658
+ defaultModelsExpandDepth: 1,
659
+ defaultModelExpandDepth: 1,
660
+ });
661
+ };
662
+ </script>
663
+ </body>
664
+ </html>`;
665
+ }
666
+ }
667
+ // src/openapi/decorators.ts
668
+ init_metadata();
669
+ function ApiTags(...tags) {
670
+ return (target) => {
671
+ const existingTags = getApiMetadata(target, "api:tags") ?? [];
672
+ const combined = [...new Set([...existingTags, ...tags])];
673
+ setApiMetadata(target, "api:tags", combined);
674
+ return target;
675
+ };
676
+ }
677
+ function ApiBearerAuth(name = "bearer", options) {
678
+ return function(target, propertyKey) {
679
+ const security = [{ [name]: [] }];
680
+ const targetObj = propertyKey ? target : target;
681
+ const store = propertyKey ? getApiMethodMetadata : getApiMetadata;
682
+ const setSt = propertyKey ? setApiMethodMetadata : setApiMetadata;
683
+ const existingSecurity = store(targetObj, "api:security") ?? [];
684
+ setSt(targetObj, "api:security", [...existingSecurity, ...security]);
685
+ return propertyKey ? descriptor : target;
686
+ };
687
+ }
688
+ function ApiBasicAuth(name = "basic") {
689
+ return function(target, propertyKey) {
690
+ const security = [{ [name]: [] }];
691
+ const targetObj = propertyKey ? target : target;
692
+ const store = propertyKey ? getApiMethodMetadata : getApiMetadata;
693
+ const setSt = propertyKey ? setApiMethodMetadata : setApiMetadata;
694
+ const existingSecurity = store(targetObj, "api:security") ?? [];
695
+ setSt(targetObj, "api:security", [...existingSecurity, ...security]);
696
+ return propertyKey ? descriptor : target;
697
+ };
698
+ }
699
+ function ApiApiKey(options, name = "api_key") {
700
+ return function(target, propertyKey) {
701
+ const security = [{ [name]: [] }];
702
+ const targetObj = propertyKey ? target : target;
703
+ const store = propertyKey ? getApiMethodMetadata : getApiMetadata;
704
+ const setSt = propertyKey ? setApiMethodMetadata : setApiMetadata;
705
+ const existingSecurity = store(targetObj, "api:security") ?? [];
706
+ setSt(targetObj, `api:security:scheme:${name}`, options);
707
+ setSt(targetObj, "api:security", [...existingSecurity, ...security]);
708
+ return propertyKey ? descriptor : target;
709
+ };
710
+ }
711
+ function ApiExcludeController() {
712
+ return (target) => {
713
+ setApiMetadata(target, "api:exclude", true);
714
+ return target;
715
+ };
716
+ }
717
+ function ApiOperation(options) {
718
+ return (target, propertyKey) => {
719
+ setApiMethodMetadata(target, `api:operation:${String(propertyKey)}`, options);
720
+ };
721
+ }
722
+ function ApiResponse(options) {
723
+ return (target, propertyKey) => {
724
+ const key = `api:responses:${String(propertyKey)}`;
725
+ const existing = getApiMethodMetadata(target, key) ?? [];
726
+ existing.push(options);
727
+ setApiMethodMetadata(target, key, existing);
728
+ };
729
+ }
730
+ function ApiParam(options) {
731
+ return (target, propertyKey) => {
732
+ const key = `api:params:${String(propertyKey)}`;
733
+ const existing = getApiMethodMetadata(target, key) ?? [];
734
+ existing.push(options);
735
+ setApiMethodMetadata(target, key, existing);
736
+ };
737
+ }
738
+ function ApiQuery(options) {
739
+ return (target, propertyKey) => {
740
+ const key = `api:query:${String(propertyKey)}`;
741
+ const existing = getApiMethodMetadata(target, key) ?? [];
742
+ existing.push(options);
743
+ setApiMethodMetadata(target, key, existing);
744
+ };
745
+ }
746
+ function ApiHeader(options) {
747
+ return (target, propertyKey) => {
748
+ const key = `api:headers:${String(propertyKey)}`;
749
+ const existing = getApiMethodMetadata(target, key) ?? [];
750
+ existing.push(options);
751
+ setApiMethodMetadata(target, key, existing);
752
+ };
753
+ }
754
+ function ApiBody(options) {
755
+ return (target, propertyKey) => {
756
+ setApiMethodMetadata(target, `api:body:${String(propertyKey)}`, options);
757
+ };
758
+ }
759
+ function ApiExcludeEndpoint() {
760
+ return (target, propertyKey) => {
761
+ setApiMethodMetadata(target, `api:exclude:${String(propertyKey)}`, true);
762
+ };
763
+ }
764
+ function ApiProperty(options) {
765
+ return (target, propertyKey) => {
766
+ const opts = { ...options, required: options?.required !== false };
767
+ setApiPropertyMetadata(target, propertyKey, opts);
768
+ };
769
+ }
770
+ function ApiPropertyOptional(options) {
771
+ return (target, propertyKey) => {
772
+ const opts = { ...options, required: false };
773
+ setApiPropertyMetadata(target, propertyKey, opts);
774
+ };
775
+ }
776
+ export {
777
+ SwaggerModule,
778
+ SchemaGenerator,
779
+ RouteScanner,
780
+ DocumentBuilder,
781
+ ApiTags,
782
+ ApiResponse,
783
+ ApiQuery,
784
+ ApiPropertyOptional,
785
+ ApiProperty,
786
+ ApiParam,
787
+ ApiOperation,
788
+ ApiHeader,
789
+ ApiExcludeEndpoint,
790
+ ApiExcludeController,
791
+ ApiBody,
792
+ ApiBearerAuth,
793
+ ApiBasicAuth,
794
+ ApiApiKey
795
+ };