@engjts/nexus 0.1.8 → 0.1.9

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 (205) hide show
  1. package/package.json +1 -1
  2. package/BENCHMARK_REPORT.md +0 -343
  3. package/documentation/01-getting-started.md +0 -240
  4. package/documentation/02-context.md +0 -335
  5. package/documentation/03-routing.md +0 -397
  6. package/documentation/04-middleware.md +0 -483
  7. package/documentation/05-validation.md +0 -514
  8. package/documentation/06-error-handling.md +0 -465
  9. package/documentation/07-performance.md +0 -364
  10. package/documentation/08-adapters.md +0 -470
  11. package/documentation/09-api-reference.md +0 -548
  12. package/documentation/10-examples.md +0 -582
  13. package/documentation/11-deployment.md +0 -477
  14. package/documentation/12-sentry.md +0 -620
  15. package/documentation/13-sentry-data-storage.md +0 -996
  16. package/documentation/14-sentry-data-reference.md +0 -457
  17. package/documentation/15-sentry-summary.md +0 -409
  18. package/documentation/16-alerts-system.md +0 -745
  19. package/documentation/17-alert-adapters.md +0 -696
  20. package/documentation/18-alerts-implementation-summary.md +0 -385
  21. package/documentation/19-class-based-routing.md +0 -840
  22. package/documentation/20-websocket-realtime.md +0 -813
  23. package/documentation/21-cache-system.md +0 -510
  24. package/documentation/22-job-queue.md +0 -772
  25. package/documentation/23-sentry-plugin.md +0 -551
  26. package/documentation/24-testing-utilities.md +0 -1287
  27. package/documentation/25-api-versioning.md +0 -533
  28. package/documentation/26-context-store.md +0 -607
  29. package/documentation/27-dependency-injection.md +0 -329
  30. package/documentation/28-lifecycle-hooks.md +0 -521
  31. package/documentation/29-package-structure.md +0 -196
  32. package/documentation/30-plugin-system.md +0 -414
  33. package/documentation/31-jwt-authentication.md +0 -597
  34. package/documentation/32-cli.md +0 -268
  35. package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
  36. package/documentation/ALERTS-INDEX.md +0 -330
  37. package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
  38. package/documentation/README.md +0 -178
  39. package/documentation/index.html +0 -34
  40. package/modern_framework_paper.md +0 -1870
  41. package/public/css/style.css +0 -87
  42. package/public/index.html +0 -34
  43. package/public/js/app.js +0 -27
  44. package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
  45. package/src/advanced/cache/MultiTierCache.ts +0 -194
  46. package/src/advanced/cache/RedisCacheStore.ts +0 -341
  47. package/src/advanced/cache/index.ts +0 -5
  48. package/src/advanced/cache/types.ts +0 -40
  49. package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
  50. package/src/advanced/graphql/index.ts +0 -22
  51. package/src/advanced/graphql/server.ts +0 -252
  52. package/src/advanced/graphql/types.ts +0 -42
  53. package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
  54. package/src/advanced/jobs/JobQueue.ts +0 -556
  55. package/src/advanced/jobs/RedisQueueStore.ts +0 -367
  56. package/src/advanced/jobs/index.ts +0 -5
  57. package/src/advanced/jobs/types.ts +0 -70
  58. package/src/advanced/observability/APMManager.ts +0 -163
  59. package/src/advanced/observability/AlertManager.ts +0 -109
  60. package/src/advanced/observability/MetricRegistry.ts +0 -151
  61. package/src/advanced/observability/ObservabilityCenter.ts +0 -304
  62. package/src/advanced/observability/StructuredLogger.ts +0 -154
  63. package/src/advanced/observability/TracingManager.ts +0 -117
  64. package/src/advanced/observability/adapters.ts +0 -304
  65. package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
  66. package/src/advanced/observability/index.ts +0 -11
  67. package/src/advanced/observability/types.ts +0 -174
  68. package/src/advanced/playground/extractPathParams.ts +0 -6
  69. package/src/advanced/playground/generateFieldExample.ts +0 -31
  70. package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
  71. package/src/advanced/playground/generateSummary.ts +0 -19
  72. package/src/advanced/playground/getTagFromPath.ts +0 -9
  73. package/src/advanced/playground/index.ts +0 -8
  74. package/src/advanced/playground/playground.ts +0 -250
  75. package/src/advanced/playground/types.ts +0 -49
  76. package/src/advanced/playground/zodToExample.ts +0 -16
  77. package/src/advanced/playground/zodToParams.ts +0 -15
  78. package/src/advanced/postman/buildAuth.ts +0 -31
  79. package/src/advanced/postman/buildBody.ts +0 -15
  80. package/src/advanced/postman/buildQueryParams.ts +0 -27
  81. package/src/advanced/postman/buildRequestItem.ts +0 -36
  82. package/src/advanced/postman/buildResponses.ts +0 -11
  83. package/src/advanced/postman/buildUrl.ts +0 -33
  84. package/src/advanced/postman/capitalize.ts +0 -4
  85. package/src/advanced/postman/generateCollection.ts +0 -59
  86. package/src/advanced/postman/generateEnvironment.ts +0 -34
  87. package/src/advanced/postman/generateExampleFromZod.ts +0 -21
  88. package/src/advanced/postman/generateFieldExample.ts +0 -45
  89. package/src/advanced/postman/generateName.ts +0 -20
  90. package/src/advanced/postman/generateUUID.ts +0 -11
  91. package/src/advanced/postman/getTagFromPath.ts +0 -10
  92. package/src/advanced/postman/index.ts +0 -28
  93. package/src/advanced/postman/postman.ts +0 -156
  94. package/src/advanced/postman/slugify.ts +0 -7
  95. package/src/advanced/postman/types.ts +0 -140
  96. package/src/advanced/realtime/index.ts +0 -18
  97. package/src/advanced/realtime/websocket.ts +0 -231
  98. package/src/advanced/sentry/index.ts +0 -1236
  99. package/src/advanced/sentry/types.ts +0 -355
  100. package/src/advanced/static/generateDirectoryListing.ts +0 -47
  101. package/src/advanced/static/generateETag.ts +0 -7
  102. package/src/advanced/static/getMimeType.ts +0 -9
  103. package/src/advanced/static/index.ts +0 -32
  104. package/src/advanced/static/isSafePath.ts +0 -13
  105. package/src/advanced/static/publicDir.ts +0 -21
  106. package/src/advanced/static/serveStatic.ts +0 -225
  107. package/src/advanced/static/spa.ts +0 -24
  108. package/src/advanced/static/types.ts +0 -159
  109. package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
  110. package/src/advanced/swagger/buildOperation.ts +0 -61
  111. package/src/advanced/swagger/buildParameters.ts +0 -61
  112. package/src/advanced/swagger/buildRequestBody.ts +0 -21
  113. package/src/advanced/swagger/buildResponses.ts +0 -54
  114. package/src/advanced/swagger/capitalize.ts +0 -5
  115. package/src/advanced/swagger/convertPath.ts +0 -9
  116. package/src/advanced/swagger/createSwagger.ts +0 -12
  117. package/src/advanced/swagger/generateOperationId.ts +0 -21
  118. package/src/advanced/swagger/generateSpec.ts +0 -105
  119. package/src/advanced/swagger/generateSummary.ts +0 -24
  120. package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
  121. package/src/advanced/swagger/generateThemeCss.ts +0 -53
  122. package/src/advanced/swagger/index.ts +0 -25
  123. package/src/advanced/swagger/swagger.ts +0 -237
  124. package/src/advanced/swagger/types.ts +0 -206
  125. package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
  126. package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
  127. package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
  128. package/src/advanced/testing/factory.ts +0 -509
  129. package/src/advanced/testing/harness.ts +0 -612
  130. package/src/advanced/testing/index.ts +0 -430
  131. package/src/advanced/testing/load-test.ts +0 -618
  132. package/src/advanced/testing/mock-server.ts +0 -498
  133. package/src/advanced/testing/mock.ts +0 -670
  134. package/src/cli/bin.ts +0 -9
  135. package/src/cli/cli.ts +0 -158
  136. package/src/cli/commands/add.ts +0 -178
  137. package/src/cli/commands/build.ts +0 -73
  138. package/src/cli/commands/create.ts +0 -166
  139. package/src/cli/commands/dev.ts +0 -85
  140. package/src/cli/commands/generate.ts +0 -99
  141. package/src/cli/commands/help.ts +0 -95
  142. package/src/cli/commands/init.ts +0 -91
  143. package/src/cli/commands/version.ts +0 -38
  144. package/src/cli/index.ts +0 -6
  145. package/src/cli/templates/generators.ts +0 -359
  146. package/src/cli/templates/index.ts +0 -680
  147. package/src/cli/utils/exec.ts +0 -52
  148. package/src/cli/utils/file-system.ts +0 -78
  149. package/src/cli/utils/logger.ts +0 -111
  150. package/src/core/adapter.ts +0 -88
  151. package/src/core/application.ts +0 -1453
  152. package/src/core/context-pool.ts +0 -79
  153. package/src/core/context.ts +0 -856
  154. package/src/core/index.ts +0 -94
  155. package/src/core/middleware.ts +0 -272
  156. package/src/core/performance/buffer-pool.ts +0 -108
  157. package/src/core/performance/middleware-optimizer.ts +0 -162
  158. package/src/core/plugin/PluginManager.ts +0 -435
  159. package/src/core/plugin/builder.ts +0 -358
  160. package/src/core/plugin/index.ts +0 -50
  161. package/src/core/plugin/types.ts +0 -214
  162. package/src/core/router/file-router.ts +0 -623
  163. package/src/core/router/index.ts +0 -260
  164. package/src/core/router/radix-tree.ts +0 -242
  165. package/src/core/serializer.ts +0 -397
  166. package/src/core/store/index.ts +0 -30
  167. package/src/core/store/registry.ts +0 -178
  168. package/src/core/store/request-store.ts +0 -240
  169. package/src/core/store/types.ts +0 -233
  170. package/src/core/types.ts +0 -616
  171. package/src/database/adapter.ts +0 -35
  172. package/src/database/adapters/index.ts +0 -1
  173. package/src/database/adapters/mysql.ts +0 -669
  174. package/src/database/database.ts +0 -70
  175. package/src/database/dialect.ts +0 -388
  176. package/src/database/index.ts +0 -12
  177. package/src/database/migrations.ts +0 -86
  178. package/src/database/optimizer.ts +0 -125
  179. package/src/database/query-builder.ts +0 -404
  180. package/src/database/realtime.ts +0 -53
  181. package/src/database/schema.ts +0 -71
  182. package/src/database/transactions.ts +0 -56
  183. package/src/database/types.ts +0 -87
  184. package/src/deployment/cluster.ts +0 -471
  185. package/src/deployment/config.ts +0 -454
  186. package/src/deployment/docker.ts +0 -599
  187. package/src/deployment/graceful-shutdown.ts +0 -373
  188. package/src/deployment/index.ts +0 -56
  189. package/src/index.ts +0 -281
  190. package/src/security/adapter.ts +0 -318
  191. package/src/security/auth/JWTPlugin.ts +0 -234
  192. package/src/security/auth/JWTProvider.ts +0 -316
  193. package/src/security/auth/adapter.ts +0 -12
  194. package/src/security/auth/jwt.ts +0 -234
  195. package/src/security/auth/middleware.ts +0 -188
  196. package/src/security/csrf.ts +0 -220
  197. package/src/security/headers.ts +0 -108
  198. package/src/security/index.ts +0 -60
  199. package/src/security/rate-limit/adapter.ts +0 -7
  200. package/src/security/rate-limit/memory.ts +0 -108
  201. package/src/security/rate-limit/middleware.ts +0 -181
  202. package/src/security/sanitization.ts +0 -75
  203. package/src/security/types.ts +0 -240
  204. package/src/security/utils.ts +0 -52
  205. package/tsconfig.json +0 -39
@@ -1,225 +0,0 @@
1
- import { existsSync, statSync, createReadStream } from 'fs';
2
- import { resolve, join, extname } from 'path/posix';
3
- import { generateDirectoryListing } from './generateDirectoryListing';
4
- import { isSafePath } from './isSafePath';
5
- import { generateETag } from './generateETag';
6
- import { getMimeType } from './getMimeType';
7
- import { Plugin, Handler, Response } from '../../core/types';
8
- import { StaticConfig } from './types';
9
-
10
- /**
11
- * Create static file serving feature
12
- */
13
-
14
- export function serveStatic(config: StaticConfig = {}): Plugin {
15
- const {
16
- root = './public', prefix = '', index = 'index.html', directory = false, maxAge = 86400, immutable = false, etag = true, lastModified = true, extensions, dotfiles = 'ignore', fallback, headers = {}, precompressed = false
17
- } = config;
18
-
19
- const rootPath = resolve(process.cwd(), root);
20
- const normalizedPrefix = prefix.startsWith('/') ? prefix : prefix ? `/${prefix}` : '';
21
-
22
- return {
23
- name: 'static',
24
- version: '1.0.0',
25
-
26
- install(app: any) {
27
- // Create the static file handler
28
- const staticHandler: Handler = async (ctx) => {
29
- let requestPath = ctx.path;
30
-
31
- // Remove prefix if set
32
- if (normalizedPrefix && requestPath.startsWith(normalizedPrefix)) {
33
- requestPath = requestPath.slice(normalizedPrefix.length) || '/';
34
- } else if (normalizedPrefix) {
35
- // Path doesn't match prefix, skip
36
- return { statusCode: 404, headers: {}, body: 'Not Found' };
37
- }
38
-
39
- // Decode URL
40
- try {
41
- requestPath = decodeURIComponent(requestPath);
42
- } catch {
43
- return { statusCode: 400, headers: {}, body: 'Bad Request' };
44
- }
45
-
46
- // Remove leading slash for joining
47
- const cleanPath = requestPath.startsWith('/') ? requestPath.slice(1) : requestPath;
48
-
49
- // Security: Check for directory traversal
50
- if (!isSafePath(cleanPath, rootPath)) {
51
- return { statusCode: 403, headers: {}, body: 'Forbidden' };
52
- }
53
-
54
- const filePath = join(rootPath, cleanPath);
55
-
56
- // Handle dotfiles
57
- const basename = cleanPath.split('/').pop() || '';
58
- if (basename.startsWith('.')) {
59
- if (dotfiles === 'deny') {
60
- return { statusCode: 403, headers: {}, body: 'Forbidden' };
61
- }
62
- if (dotfiles === 'ignore') {
63
- return { statusCode: 404, headers: {}, body: 'Not Found' };
64
- }
65
- }
66
-
67
- // Check if file/directory exists
68
- if (!existsSync(filePath)) {
69
- // Try fallback for SPA
70
- if (fallback) {
71
- const fallbackPath = join(rootPath, fallback);
72
- if (existsSync(fallbackPath)) {
73
- return serveFile(fallbackPath, ctx);
74
- }
75
- }
76
- return { statusCode: 404, headers: {}, body: 'Not Found' };
77
- }
78
-
79
- const stats = statSync(filePath);
80
-
81
- // Handle directory
82
- if (stats.isDirectory()) {
83
- // Try index file(s)
84
- if (index !== false) {
85
- const indexFiles = Array.isArray(index) ? index : [index];
86
- for (const indexFile of indexFiles) {
87
- const indexPath = join(filePath, indexFile);
88
- if (existsSync(indexPath)) {
89
- return serveFile(indexPath, ctx);
90
- }
91
- }
92
- }
93
-
94
- // Directory listing
95
- if (directory) {
96
- const html = await generateDirectoryListing(filePath, requestPath);
97
- return {
98
- statusCode: 200,
99
- headers: { 'Content-Type': 'text/html; charset=utf-8' },
100
- body: html
101
- };
102
- }
103
-
104
- return { statusCode: 404, headers: {}, body: 'Not Found' };
105
- }
106
-
107
- // Check extension whitelist
108
- const ext = extname(filePath);
109
- if (extensions && !extensions.includes(ext)) {
110
- return { statusCode: 403, headers: {}, body: 'Forbidden' };
111
- }
112
-
113
- return serveFile(filePath, ctx);
114
- };
115
-
116
- // Helper to serve a file
117
- async function serveFile(filePath: string, ctx: any): Promise<Response> {
118
- const stats = statSync(filePath);
119
- const ext = extname(filePath);
120
- const mimeType = getMimeType(ext);
121
-
122
- const responseHeaders: Record<string, string> = {
123
- 'Content-Type': mimeType,
124
- 'Content-Length': stats.size.toString(),
125
- ...headers
126
- };
127
-
128
- // Cache headers
129
- let cacheControl = `public, max-age=${maxAge}`;
130
- if (immutable) {
131
- cacheControl += ', immutable';
132
- }
133
- responseHeaders['Cache-Control'] = cacheControl;
134
-
135
- // ETag
136
- if (etag) {
137
- const etagValue = generateETag(stats);
138
- responseHeaders['ETag'] = etagValue;
139
-
140
- // Check If-None-Match
141
- const ifNoneMatch = ctx.headers['if-none-match'];
142
- if (ifNoneMatch === etagValue) {
143
- return { statusCode: 304, headers: responseHeaders, body: '' };
144
- }
145
- }
146
-
147
- // Last-Modified
148
- if (lastModified) {
149
- const lastMod = stats.mtime.toUTCString();
150
- responseHeaders['Last-Modified'] = lastMod;
151
-
152
- // Check If-Modified-Since
153
- const ifModifiedSince = ctx.headers['if-modified-since'];
154
- if (ifModifiedSince) {
155
- const ifModDate = new Date(ifModifiedSince);
156
- if (stats.mtime <= ifModDate) {
157
- return { statusCode: 304, headers: responseHeaders, body: '' };
158
- }
159
- }
160
- }
161
-
162
- // Check for pre-compressed version
163
- if (precompressed) {
164
- const acceptEncoding = ctx.headers['accept-encoding'] || '';
165
- const compressions = Array.isArray(precompressed)
166
- ? precompressed
167
- : ['br', 'gzip'];
168
-
169
- for (const encoding of compressions) {
170
- if (acceptEncoding.includes(encoding)) {
171
- const ext = encoding === 'br' ? '.br' : '.gz';
172
- const compressedPath = filePath + ext;
173
- if (existsSync(compressedPath)) {
174
- const compressedStats = statSync(compressedPath);
175
- responseHeaders['Content-Encoding'] = encoding;
176
- responseHeaders['Content-Length'] = compressedStats.size.toString();
177
- responseHeaders['Vary'] = 'Accept-Encoding';
178
-
179
- return {
180
- statusCode: 200,
181
- headers: responseHeaders,
182
- body: '',
183
- stream: createReadStream(compressedPath)
184
- };
185
- }
186
- }
187
- }
188
- }
189
-
190
- // Stream the file
191
- return {
192
- statusCode: 200,
193
- headers: responseHeaders,
194
- body: '',
195
- stream: createReadStream(filePath)
196
- };
197
- }
198
-
199
- // Register static file handler
200
- if (normalizedPrefix) {
201
- // With prefix: only serve files under that prefix as routes
202
- app.get(`${normalizedPrefix}`, staticHandler);
203
- app.get(`${normalizedPrefix}/*`, staticHandler);
204
- } else {
205
- // Without prefix: register as fallback handler
206
- // This is called when no routes match, before 404
207
- if (typeof app.setFallbackHandler === 'function') {
208
- app.setFallbackHandler(staticHandler);
209
- } else {
210
- // Fallback: register as low-priority wildcard routes
211
- // NOTE: This should be registered LAST after all API routes
212
- app.get('/', staticHandler);
213
- app.get('/*', staticHandler);
214
- }
215
- }
216
-
217
- if (app.config?.debug) {
218
- console.log(`📁 Static files: ${rootPath}`);
219
- if (normalizedPrefix) {
220
- console.log(` Prefix: ${normalizedPrefix}`);
221
- }
222
- }
223
- }
224
- };
225
- }
@@ -1,24 +0,0 @@
1
- import { Plugin } from '../../core/types';
2
- import { serveStatic } from './serveStatic';
3
-
4
- /**
5
- * Create SPA (Single Page Application) static serving
6
- * Falls back to index.html for client-side routing
7
- *
8
- * @example
9
- * ```typescript
10
- * app.plugin(spa()); // SPA from ./public
11
- * app.plugin(spa('./dist')); // SPA from ./dist
12
- * ```
13
- */
14
-
15
- export function spa(root = './public'): Plugin {
16
- return serveStatic({
17
- root,
18
- fallback: 'index.html',
19
- maxAge: 0, // No cache for HTML
20
- etag: true
21
- });
22
- }
23
-
24
- export type { Plugin };
@@ -1,159 +0,0 @@
1
- /**
2
- * MIME types mapping
3
- */
4
-
5
- export const MIME_TYPES: Record<string, string> = {
6
- // Text
7
- '.html': 'text/html; charset=utf-8',
8
- '.htm': 'text/html; charset=utf-8',
9
- '.css': 'text/css; charset=utf-8',
10
- '.js': 'text/javascript; charset=utf-8',
11
- '.mjs': 'text/javascript; charset=utf-8',
12
- '.json': 'application/json; charset=utf-8',
13
- '.xml': 'application/xml; charset=utf-8',
14
- '.txt': 'text/plain; charset=utf-8',
15
- '.md': 'text/markdown; charset=utf-8',
16
- '.csv': 'text/csv; charset=utf-8',
17
-
18
- // Images
19
- '.png': 'image/png',
20
- '.jpg': 'image/jpeg',
21
- '.jpeg': 'image/jpeg',
22
- '.gif': 'image/gif',
23
- '.webp': 'image/webp',
24
- '.svg': 'image/svg+xml',
25
- '.ico': 'image/x-icon',
26
- '.bmp': 'image/bmp',
27
- '.avif': 'image/avif',
28
-
29
- // Fonts
30
- '.woff': 'font/woff',
31
- '.woff2': 'font/woff2',
32
- '.ttf': 'font/ttf',
33
- '.otf': 'font/otf',
34
- '.eot': 'application/vnd.ms-fontobject',
35
-
36
- // Audio
37
- '.mp3': 'audio/mpeg',
38
- '.wav': 'audio/wav',
39
- '.ogg': 'audio/ogg',
40
- '.m4a': 'audio/mp4',
41
- '.flac': 'audio/flac',
42
-
43
- // Video
44
- '.mp4': 'video/mp4',
45
- '.webm': 'video/webm',
46
- '.avi': 'video/x-msvideo',
47
- '.mov': 'video/quicktime',
48
- '.mkv': 'video/x-matroska',
49
-
50
- // Documents
51
- '.pdf': 'application/pdf',
52
- '.doc': 'application/msword',
53
- '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
54
- '.xls': 'application/vnd.ms-excel',
55
- '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
56
- '.ppt': 'application/vnd.ms-powerpoint',
57
- '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
58
-
59
- // Archives
60
- '.zip': 'application/zip',
61
- '.rar': 'application/vnd.rar',
62
- '.7z': 'application/x-7z-compressed',
63
- '.tar': 'application/x-tar',
64
- '.gz': 'application/gzip',
65
-
66
- // Data
67
- '.wasm': 'application/wasm',
68
- '.map': 'application/json',
69
-
70
- // Default
71
- '': 'application/octet-stream'
72
- };
73
-
74
-
75
- /**
76
- * Static file serving configuration
77
- */
78
- export interface StaticConfig {
79
- /**
80
- * Root directory to serve files from
81
- * @default './public'
82
- */
83
- root?: string;
84
-
85
- /**
86
- * URL prefix for static files
87
- * @default '' (serve from root)
88
- * @example '/static' → /static/image.png serves ./public/image.png
89
- */
90
- prefix?: string;
91
-
92
- /**
93
- * Default file to serve for directory requests
94
- * @default 'index.html'
95
- */
96
- index?: string | string[] | false;
97
-
98
- /**
99
- * Enable directory listing
100
- * @default false
101
- */
102
- directory?: boolean;
103
-
104
- /**
105
- * Maximum age for Cache-Control header (in seconds)
106
- * @default 86400 (1 day)
107
- */
108
- maxAge?: number;
109
-
110
- /**
111
- * Enable immutable caching (for versioned assets)
112
- * @default false
113
- */
114
- immutable?: boolean;
115
-
116
- /**
117
- * Enable ETag generation
118
- * @default true
119
- */
120
- etag?: boolean;
121
-
122
- /**
123
- * Enable Last-Modified header
124
- * @default true
125
- */
126
- lastModified?: boolean;
127
-
128
- /**
129
- * Allowed file extensions (whitelist)
130
- * @default undefined (allow all)
131
- * @example ['.html', '.css', '.js', '.png']
132
- */
133
- extensions?: string[];
134
-
135
- /**
136
- * Hidden files (dotfiles) handling
137
- * @default 'ignore'
138
- */
139
- dotfiles?: 'allow' | 'deny' | 'ignore';
140
-
141
- /**
142
- * Fallback file for SPA routing
143
- * @default undefined
144
- * @example 'index.html' for SPA
145
- */
146
- fallback?: string;
147
-
148
- /**
149
- * Custom headers to add to responses
150
- */
151
- headers?: Record<string, string>;
152
-
153
- /**
154
- * Enable gzip/brotli pre-compressed files
155
- * Looks for .gz or .br versions of files
156
- * @default false
157
- */
158
- precompressed?: boolean | ('gzip' | 'br')[];
159
- }
@@ -1,66 +0,0 @@
1
- import { RouteConfig } from '../../core/types';
2
- import { generateSpec } from './generateSpec';
3
- import { generateSwaggerUI } from './generateSwaggerUI';
4
- import { SwaggerConfig, StoredRoute, OpenAPISchema, OpenAPISpec } from './types';
5
-
6
- // ============================================
7
- // LEGACY EXPORTS (backward compatibility)
8
- // ============================================
9
- /**
10
- * SwaggerGenerator class for advanced/manual usage
11
- * @deprecated Use swagger() plugin instead
12
- */
13
-
14
-
15
- export class SwaggerGenerator {
16
- private config: SwaggerConfig;
17
- private routes: StoredRoute[] = [];
18
- private schemas: Map<string, OpenAPISchema> = new Map();
19
-
20
- constructor(config: SwaggerConfig = {}) {
21
- this.config = {
22
- path: '/docs',
23
- specPath: '/openapi.json',
24
- ...config,
25
- info: {
26
- title: 'API Documentation',
27
- version: '1.0.0',
28
- ...config.info
29
- }
30
- };
31
- }
32
-
33
- registerRoutes(routes: RouteConfig[]): void {
34
- this.routes.push(...routes.map(r => ({
35
- method: r.method,
36
- path: r.path,
37
- schema: r.schema,
38
- meta: r.meta
39
- })));
40
- }
41
-
42
- registerRoute(route: RouteConfig): void {
43
- this.routes.push({
44
- method: route.method,
45
- path: route.path,
46
- schema: route.schema,
47
- meta: route.meta
48
- });
49
- }
50
-
51
- registerSchema(name: string, schema: OpenAPISchema): void {
52
- this.schemas.set(name, schema);
53
- }
54
-
55
- generateSpec(): OpenAPISpec {
56
- return generateSpec(this.routes, this.schemas, this.config, '');
57
- }
58
-
59
- generateSwaggerUI(): string {
60
- return generateSwaggerUI(this.config);
61
- }
62
-
63
- getConfig(): SwaggerConfig {
64
- return this.config;
65
- }
66
- }
@@ -1,61 +0,0 @@
1
- import { buildRequestBody } from './buildRequestBody';
2
- import { buildParameters } from './buildParameters';
3
- import { buildResponses } from './buildResponses';
4
- import { capitalize } from './capitalize';
5
- import { generateOperationId } from './generateOperationId';
6
- import { generateSummary } from './generateSummary';
7
- import { StoredRoute, SwaggerConfig, OpenAPIOperation } from './types';
8
-
9
- /**
10
- * Build OpenAPI operation from route
11
- */
12
-
13
-
14
- export function buildOperation(route: StoredRoute, config: SwaggerConfig): OpenAPIOperation {
15
- const meta = route.meta || {};
16
-
17
- const operation: OpenAPIOperation = {
18
- responses: buildResponses(meta.responses, route.method)
19
- };
20
-
21
- // Auto-generate summary from path if not provided
22
- if (meta.summary) {
23
- operation.summary = meta.summary;
24
- } else {
25
- operation.summary = generateSummary(route.method, route.path);
26
- }
27
-
28
- if (meta.description) {
29
- operation.description = meta.description;
30
- }
31
-
32
- if (meta.tags && meta.tags.length > 0) {
33
- operation.tags = meta.tags;
34
- } else if (!config.hideUntagged) {
35
- // Auto-tag based on first path segment
36
- const firstSegment = route.path.split('/').filter(Boolean)[0];
37
- if (firstSegment && !firstSegment.startsWith(':')) {
38
- operation.tags = [capitalize(firstSegment)];
39
- }
40
- }
41
-
42
- if (meta.deprecated) {
43
- operation.deprecated = true;
44
- }
45
-
46
- // Generate operation ID
47
- operation.operationId = generateOperationId(route.method, route.path);
48
-
49
- // Build parameters from schema
50
- const parameters = buildParameters(route);
51
- if (parameters.length > 0) {
52
- operation.parameters = parameters;
53
- }
54
-
55
- // Build request body for POST/PUT/PATCH
56
- if (route.schema?.body && ['POST', 'PUT', 'PATCH'].includes(route.method)) {
57
- operation.requestBody = buildRequestBody(route.schema);
58
- }
59
-
60
- return operation;
61
- }
@@ -1,61 +0,0 @@
1
- import { zodToOpenAPI } from './zodToOpenAPI';
2
- import { zodSchemaToOpenAPI } from './zodSchemaToOpenAPI';
3
- import { capitalize } from './capitalize';
4
- import { StoredRoute, OpenAPIParameter, OpenAPISchema } from './types';
5
-
6
- /**
7
- * Build parameters from route schema
8
- */
9
-
10
-
11
- export function buildParameters(route: StoredRoute): OpenAPIParameter[] {
12
- const parameters: OpenAPIParameter[] = [];
13
-
14
- // Extract path parameters
15
- const pathParams = route.path.match(/:(\w+)/g);
16
- if (pathParams) {
17
- for (const param of pathParams) {
18
- const name = param.slice(1);
19
- const schemaFromZod = zodToOpenAPI(route.schema?.params, name);
20
- parameters.push({
21
- name,
22
- in: 'path',
23
- required: true,
24
- description: `${capitalize(name)} parameter`,
25
- schema: schemaFromZod || { type: 'string' }
26
- });
27
- }
28
- }
29
-
30
- // Add query parameters from schema
31
- if (route.schema?.query) {
32
- const querySchema = zodSchemaToOpenAPI(route.schema.query);
33
- if (querySchema.properties) {
34
- for (const [name, schema] of Object.entries(querySchema.properties)) {
35
- parameters.push({
36
- name,
37
- in: 'query',
38
- required: querySchema.required?.includes(name) || false,
39
- schema: schema as OpenAPISchema
40
- });
41
- }
42
- }
43
- }
44
-
45
- // Add header parameters from schema
46
- if (route.schema?.headers) {
47
- const headerSchema = zodSchemaToOpenAPI(route.schema.headers);
48
- if (headerSchema.properties) {
49
- for (const [name, schema] of Object.entries(headerSchema.properties)) {
50
- parameters.push({
51
- name,
52
- in: 'header',
53
- required: headerSchema.required?.includes(name) || false,
54
- schema: schema as OpenAPISchema
55
- });
56
- }
57
- }
58
- }
59
-
60
- return parameters;
61
- }
@@ -1,21 +0,0 @@
1
- import { zodSchemaToOpenAPI } from './zodSchemaToOpenAPI';
2
- import { SchemaConfig } from '../../core/types';
3
- import { OpenAPIRequestBody, OpenAPISchema } from './types';
4
-
5
- /**
6
- * Build request body from schema
7
- */
8
-
9
-
10
- export function buildRequestBody(schema: SchemaConfig): OpenAPIRequestBody {
11
- const bodySchema = schema.body ? zodSchemaToOpenAPI(schema.body) : { type: 'object' };
12
-
13
- return {
14
- required: true,
15
- content: {
16
- 'application/json': {
17
- schema: bodySchema as OpenAPISchema
18
- }
19
- }
20
- };
21
- }
@@ -1,54 +0,0 @@
1
- import { HTTPMethod } from '../../core/types';
2
- import { OpenAPIResponse } from './types';
3
-
4
- /**
5
- * Build response objects
6
- */
7
-
8
-
9
- export function buildResponses(
10
- responses?: Record<number, string>,
11
- method?: HTTPMethod
12
- ): Record<string, OpenAPIResponse> {
13
- const result: Record<string, OpenAPIResponse> = {};
14
-
15
- if (responses) {
16
- for (const [code, description] of Object.entries(responses)) {
17
- result[code] = {
18
- description,
19
- content: {
20
- 'application/json': {
21
- schema: { type: 'object' }
22
- }
23
- }
24
- };
25
- }
26
- }
27
-
28
- // Add default responses based on method
29
- if (!result['200'] && !result['201'] && !result['204']) {
30
- if (method === 'POST') {
31
- result['201'] = {
32
- description: 'Created successfully',
33
- content: { 'application/json': { schema: { type: 'object' } } }
34
- };
35
- } else if (method === 'DELETE') {
36
- result['204'] = { description: 'Deleted successfully' };
37
- } else {
38
- result['200'] = {
39
- description: 'Successful response',
40
- content: { 'application/json': { schema: { type: 'object' } } }
41
- };
42
- }
43
- }
44
-
45
- // Add common error responses
46
- if (!result['400']) {
47
- result['400'] = { description: 'Bad request' };
48
- }
49
- if (!result['500']) {
50
- result['500'] = { description: 'Internal server error' };
51
- }
52
-
53
- return result;
54
- }
@@ -1,5 +0,0 @@
1
-
2
-
3
- export function capitalize(str: string): string {
4
- return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
5
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Convert Express-style path to OpenAPI path
3
- * :id -> {id}
4
- */
5
-
6
-
7
- export function convertPath(path: string): string {
8
- return path.replace(/:(\w+)/g, '{$1}');
9
- }