@stacksjs/bun-router 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/container/service-provider.d.ts +3 -3
- package/dist/development/performance-profiler.d.ts +3 -3
- package/dist/development/route-debugger.d.ts +1 -1
- package/dist/development/route-inspector.d.ts +2 -2
- package/dist/observability/integration.d.ts +1 -1
- package/dist/response/macros.d.ts +1 -1
- package/dist/router/index.d.ts +7 -7
- package/dist/router/router.d.ts +0 -32
- package/dist/testing/performance-testing.d.ts +2 -2
- package/dist/testing/test-client.d.ts +1 -1
- package/dist/testing/websocket-testing.d.ts +1 -1
- package/package.json +2 -3
- package/src/auth.ts +0 -489
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -786
- package/src/container/contextual-binding.ts +0 -606
- package/src/container/decorators.ts +0 -368
- package/src/container/index.ts +0 -49
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -733
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -623
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -718
- package/src/index.ts +0 -66
- package/src/middleware/auth.ts +0 -220
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -142
- package/src/middleware/csrf.ts +0 -166
- package/src/middleware/ddos_protection.ts +0 -279
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -275
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -453
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -540
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -945
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -251
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -638
- package/src/middleware/request_tracer.ts +0 -653
- package/src/middleware/response_cache.ts +0 -778
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -109
- package/src/request/enhanced-request.ts +0 -876
- package/src/request/macros.ts +0 -822
- package/src/response/macros.ts +0 -665
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -697
- package/src/router/file-streaming.ts +0 -383
- package/src/router/fluent-routing.ts +0 -866
- package/src/router/group-organization.ts +0 -229
- package/src/router/handler-resolver.ts +0 -327
- package/src/router/http-methods.ts +0 -407
- package/src/router/index.ts +0 -193
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -234
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -302
- package/src/router/route-building.ts +0 -221
- package/src/router/route-compiler.ts +0 -691
- package/src/router/route-matching.ts +0 -368
- package/src/router/route-trie.ts +0 -450
- package/src/router/router.ts +0 -1616
- package/src/router/server.ts +0 -684
- package/src/router/validation-integration.ts +0 -449
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -448
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -422
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -372
- package/src/types.ts +0 -2123
- package/src/url.ts +0 -131
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -395
- package/src/validation/validator.ts +0 -688
- package/src/websocket/clustering.ts +0 -769
package/src/docs.ts
DELETED
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
import { join } from 'node:path'
|
|
2
|
-
import process from 'node:process'
|
|
3
|
-
|
|
4
|
-
interface DocsOptions {
|
|
5
|
-
verbose?: boolean
|
|
6
|
-
output?: string
|
|
7
|
-
groupBy?: 'path' | 'method' | 'tag'
|
|
8
|
-
includeExamples?: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface RouteDoc {
|
|
12
|
-
path: string
|
|
13
|
-
method: string
|
|
14
|
-
description?: string
|
|
15
|
-
params?: { [key: string]: string }
|
|
16
|
-
query?: { [key: string]: string }
|
|
17
|
-
body?: { [key: string]: string }
|
|
18
|
-
responses?: { [key: string]: string }
|
|
19
|
-
middleware?: string[]
|
|
20
|
-
tags?: string[]
|
|
21
|
-
examples?: {
|
|
22
|
-
request?: string
|
|
23
|
-
response?: string
|
|
24
|
-
}[]
|
|
25
|
-
deprecated?: boolean
|
|
26
|
-
security?: string[]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Extracts route parameters from a path
|
|
31
|
-
* @example "/users/{id}" -> { id: "string" }
|
|
32
|
-
*/
|
|
33
|
-
function extractRouteParams(path: string): { [key: string]: string } {
|
|
34
|
-
const params: { [key: string]: string } = {}
|
|
35
|
-
const matches = path.match(/\{([^}]+)\}/g)
|
|
36
|
-
|
|
37
|
-
if (matches) {
|
|
38
|
-
matches.forEach((match) => {
|
|
39
|
-
const param = match.slice(1, -1)
|
|
40
|
-
// Check for type annotations in the parameter name
|
|
41
|
-
const [name, type] = param.split(':')
|
|
42
|
-
params[name] = type || 'string'
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return params
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Attempts to load JSDoc comments from an action handler file
|
|
51
|
-
*/
|
|
52
|
-
async function loadActionDocs(handlerPath: string): Promise<Partial<RouteDoc>> {
|
|
53
|
-
try {
|
|
54
|
-
const fullPath = join(process.cwd(), 'src/actions', `${handlerPath.replace(/\//g, '_').toLowerCase()}.ts`)
|
|
55
|
-
const source = await Bun.file(fullPath).text()
|
|
56
|
-
|
|
57
|
-
// Basic JSDoc parser
|
|
58
|
-
const docComment = source.match(/\/\*\*([\s\S]*?)\*\//)
|
|
59
|
-
if (!docComment)
|
|
60
|
-
return {}
|
|
61
|
-
|
|
62
|
-
const doc = docComment[1]
|
|
63
|
-
|
|
64
|
-
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
65
|
-
const description = doc.match(/@description\s+(.+?)(?=@|\n\s*\*\/|$)/s)?.[1].trim() || ''
|
|
66
|
-
const params: { [key: string]: string } = {}
|
|
67
|
-
const query: { [key: string]: string } = {}
|
|
68
|
-
const body: { [key: string]: string } = {}
|
|
69
|
-
const responses: { [key: string]: string } = {}
|
|
70
|
-
const examples: { request?: string, response?: string }[] = []
|
|
71
|
-
const tags: string[] = []
|
|
72
|
-
const security: string[] = []
|
|
73
|
-
|
|
74
|
-
// Parse @tags
|
|
75
|
-
const tagMatches = doc.match(/@tags?\s+(.+)/g)
|
|
76
|
-
if (tagMatches) {
|
|
77
|
-
tagMatches.forEach((match) => {
|
|
78
|
-
const tag = match.replace(/@tags?\s+/, '').trim()
|
|
79
|
-
tags.push(...tag.split(/\s*,\s*/))
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Parse @security
|
|
84
|
-
const securityMatches = doc.match(/@security\s+(.+)/g)
|
|
85
|
-
if (securityMatches) {
|
|
86
|
-
securityMatches.forEach((match) => {
|
|
87
|
-
const scheme = match.replace(/@security\s+/, '').trim()
|
|
88
|
-
security.push(scheme)
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Parse @param with enhanced type support
|
|
93
|
-
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
94
|
-
const paramMatches = doc.matchAll(/@param\s+\{([^}]+)\}\s+(\w+(?:\.\w+)?)\s+(.+?)(?=@|\n\s*\*\/|$)/gs)
|
|
95
|
-
for (const match of paramMatches) {
|
|
96
|
-
const [, type, name, desc] = match
|
|
97
|
-
const cleanDesc = desc.trim()
|
|
98
|
-
if (name.startsWith('query.')) {
|
|
99
|
-
query[name.slice(6)] = `${type} - ${cleanDesc}`
|
|
100
|
-
}
|
|
101
|
-
else if (name.startsWith('body.')) {
|
|
102
|
-
body[name.slice(5)] = `${type} - ${cleanDesc}`
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
params[name] = `${type} - ${cleanDesc}`
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Parse @response with enhanced status code descriptions
|
|
110
|
-
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
111
|
-
const responseMatches = doc.matchAll(/@response\s+\{(\d+)\}\s+(.+?)(?=@|\n\s*\*\/|$)/gs)
|
|
112
|
-
for (const match of responseMatches) {
|
|
113
|
-
const [, code, desc] = match
|
|
114
|
-
responses[code] = desc.trim()
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Parse @example blocks
|
|
118
|
-
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
119
|
-
const exampleMatches = doc.matchAll(/@example\s+(request|response)[\t\v\f\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*\n\s*```(?:json)?\s*\n([\s\S]*?)\n\s*```/g)
|
|
120
|
-
let currentExample: { request?: string, response?: string } = {}
|
|
121
|
-
|
|
122
|
-
for (const match of exampleMatches) {
|
|
123
|
-
const [, type, content] = match
|
|
124
|
-
if (type === 'request') {
|
|
125
|
-
currentExample = { request: content.trim() }
|
|
126
|
-
}
|
|
127
|
-
else if (type === 'response') {
|
|
128
|
-
currentExample.response = content.trim()
|
|
129
|
-
examples.push(currentExample)
|
|
130
|
-
currentExample = {}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Check for @deprecated tag
|
|
135
|
-
const deprecated = doc.includes('@deprecated')
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
description,
|
|
139
|
-
params,
|
|
140
|
-
query,
|
|
141
|
-
body,
|
|
142
|
-
responses,
|
|
143
|
-
examples: examples.length > 0 ? examples : undefined,
|
|
144
|
-
tags: tags.length > 0 ? tags : undefined,
|
|
145
|
-
security: security.length > 0 ? security : undefined,
|
|
146
|
-
deprecated,
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
if (error instanceof Error) {
|
|
151
|
-
console.warn(`Failed to load docs for ${handlerPath}:`, error.message)
|
|
152
|
-
}
|
|
153
|
-
return {}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Generates markdown documentation for routes
|
|
159
|
-
*/
|
|
160
|
-
function generateMarkdown(routes: RouteDoc[], options: DocsOptions): string {
|
|
161
|
-
let markdown = '# API Reference\n\n'
|
|
162
|
-
|
|
163
|
-
// Add table of contents
|
|
164
|
-
markdown += '## Table of Contents\n\n'
|
|
165
|
-
|
|
166
|
-
// Group routes based on option
|
|
167
|
-
const groupedRoutes = routes.reduce((groups: { [key: string]: RouteDoc[] }, route) => {
|
|
168
|
-
let key: string
|
|
169
|
-
switch (options.groupBy) {
|
|
170
|
-
case 'method':
|
|
171
|
-
key = route.method
|
|
172
|
-
break
|
|
173
|
-
case 'tag':
|
|
174
|
-
if (route.tags?.length) {
|
|
175
|
-
route.tags.forEach((tag) => {
|
|
176
|
-
if (!groups[tag])
|
|
177
|
-
groups[tag] = []
|
|
178
|
-
groups[tag].push(route)
|
|
179
|
-
})
|
|
180
|
-
return groups
|
|
181
|
-
}
|
|
182
|
-
key = 'untagged'
|
|
183
|
-
break
|
|
184
|
-
default: // 'path'
|
|
185
|
-
key = route.path.split('/')[1] || 'root'
|
|
186
|
-
}
|
|
187
|
-
if (!groups[key])
|
|
188
|
-
groups[key] = []
|
|
189
|
-
groups[key].push(route)
|
|
190
|
-
return groups
|
|
191
|
-
}, {})
|
|
192
|
-
|
|
193
|
-
// Add ToC entries
|
|
194
|
-
for (const group of Object.keys(groupedRoutes).sort()) {
|
|
195
|
-
markdown += `- [${group.charAt(0).toUpperCase() + group.slice(1)}](#${group.toLowerCase()})\n`
|
|
196
|
-
}
|
|
197
|
-
markdown += '\n'
|
|
198
|
-
|
|
199
|
-
// Generate markdown for each group
|
|
200
|
-
for (const [group, routes] of Object.entries(groupedRoutes).sort()) {
|
|
201
|
-
markdown += `## ${group.charAt(0).toUpperCase() + group.slice(1)}\n\n`
|
|
202
|
-
|
|
203
|
-
for (const route of routes) {
|
|
204
|
-
const methodBadge = `})`
|
|
205
|
-
markdown += `### ${methodBadge} ${route.path}\n\n`
|
|
206
|
-
|
|
207
|
-
if (route.deprecated) {
|
|
208
|
-
markdown += '> ⚠️ **Deprecated**\n\n'
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (route.description) {
|
|
212
|
-
markdown += `${route.description}\n\n`
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (route.security?.length) {
|
|
216
|
-
markdown += '**Security:**\n\n'
|
|
217
|
-
for (const scheme of route.security) {
|
|
218
|
-
markdown += `- ${scheme}\n`
|
|
219
|
-
}
|
|
220
|
-
markdown += '\n'
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (route.middleware?.length) {
|
|
224
|
-
markdown += '**Middleware:**\n\n'
|
|
225
|
-
for (const mw of route.middleware) {
|
|
226
|
-
markdown += `- ${mw}\n`
|
|
227
|
-
}
|
|
228
|
-
markdown += '\n'
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (Object.keys(route.params || {}).length) {
|
|
232
|
-
markdown += '**URL Parameters:**\n\n'
|
|
233
|
-
markdown += '| Parameter | Description |\n'
|
|
234
|
-
markdown += '|-----------|-------------|\n'
|
|
235
|
-
for (const [name, desc] of Object.entries(route.params!)) {
|
|
236
|
-
markdown += `| ${name} | ${desc} |\n`
|
|
237
|
-
}
|
|
238
|
-
markdown += '\n'
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (Object.keys(route.query || {}).length) {
|
|
242
|
-
markdown += '**Query Parameters:**\n\n'
|
|
243
|
-
markdown += '| Parameter | Description |\n'
|
|
244
|
-
markdown += '|-----------|-------------|\n'
|
|
245
|
-
for (const [name, desc] of Object.entries(route.query!)) {
|
|
246
|
-
markdown += `| ${name} | ${desc} |\n`
|
|
247
|
-
}
|
|
248
|
-
markdown += '\n'
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (Object.keys(route.body || {}).length) {
|
|
252
|
-
markdown += '**Request Body:**\n\n'
|
|
253
|
-
markdown += '| Field | Description |\n'
|
|
254
|
-
markdown += '|-------|-------------|\n'
|
|
255
|
-
for (const [name, desc] of Object.entries(route.body!)) {
|
|
256
|
-
markdown += `| ${name} | ${desc} |\n`
|
|
257
|
-
}
|
|
258
|
-
markdown += '\n'
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (Object.keys(route.responses || {}).length) {
|
|
262
|
-
markdown += '**Responses:**\n\n'
|
|
263
|
-
markdown += '| Status | Description |\n'
|
|
264
|
-
markdown += '|--------|-------------|\n'
|
|
265
|
-
for (const [code, desc] of Object.entries(route.responses!)) {
|
|
266
|
-
markdown += `| ${code} | ${desc} |\n`
|
|
267
|
-
}
|
|
268
|
-
markdown += '\n'
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (options.includeExamples && route.examples?.length) {
|
|
272
|
-
markdown += '**Examples:**\n\n'
|
|
273
|
-
route.examples.forEach((example, index) => {
|
|
274
|
-
if (index > 0)
|
|
275
|
-
markdown += '\n'
|
|
276
|
-
if (example.request) {
|
|
277
|
-
markdown += `\`\`\`json\n# Request\n${example.request}\n\`\`\`\n\n`
|
|
278
|
-
}
|
|
279
|
-
if (example.response) {
|
|
280
|
-
markdown += `\`\`\`json\n# Response\n${example.response}\n\`\`\`\n\n`
|
|
281
|
-
}
|
|
282
|
-
})
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
markdown += '---\n\n'
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return markdown
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Get badge color for HTTP method
|
|
294
|
-
*/
|
|
295
|
-
function getMethodColor(method: string): string {
|
|
296
|
-
const colors: Record<string, string> = {
|
|
297
|
-
GET: '32CD32', // green
|
|
298
|
-
POST: '4169E1', // blue
|
|
299
|
-
PUT: 'FF8C00', // orange
|
|
300
|
-
PATCH: 'BA55D3', // purple
|
|
301
|
-
DELETE: 'DC143C', // red
|
|
302
|
-
OPTIONS: '808080', // gray
|
|
303
|
-
HEAD: '808080', // gray
|
|
304
|
-
}
|
|
305
|
-
return colors[method] || '808080'
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Generates API documentation from route definitions
|
|
310
|
-
*/
|
|
311
|
-
export async function generateApiDocs(options: DocsOptions = {}): Promise<void> {
|
|
312
|
-
const {
|
|
313
|
-
output = 'api-reference.md',
|
|
314
|
-
verbose = false,
|
|
315
|
-
groupBy = 'path',
|
|
316
|
-
includeExamples = true,
|
|
317
|
-
} = options
|
|
318
|
-
|
|
319
|
-
try {
|
|
320
|
-
// Load API routes
|
|
321
|
-
const apiPath = join(process.cwd(), 'routes/api.ts')
|
|
322
|
-
const webPath = join(process.cwd(), 'routes/web.ts')
|
|
323
|
-
|
|
324
|
-
const routes: RouteDoc[] = []
|
|
325
|
-
|
|
326
|
-
// Process API routes
|
|
327
|
-
try {
|
|
328
|
-
const apiRoutes = await import(apiPath)
|
|
329
|
-
if (apiRoutes.default) {
|
|
330
|
-
const routeDefs = Array.isArray(apiRoutes.default) ? apiRoutes.default : [apiRoutes.default]
|
|
331
|
-
for (const route of routeDefs) {
|
|
332
|
-
const routeDoc: RouteDoc = {
|
|
333
|
-
path: route.path,
|
|
334
|
-
method: route.method,
|
|
335
|
-
middleware: Array.isArray(route.middleware)
|
|
336
|
-
? route.middleware.map((m: string | ((_request: Request) => Promise<Request | Response>)) =>
|
|
337
|
-
typeof m === 'string' ? m : 'function',
|
|
338
|
-
)
|
|
339
|
-
: undefined,
|
|
340
|
-
params: extractRouteParams(route.path),
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (typeof route.handler === 'string') {
|
|
344
|
-
const actionDocs = await loadActionDocs(route.handler)
|
|
345
|
-
Object.assign(routeDoc, actionDocs)
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
routes.push(routeDoc)
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
catch {
|
|
353
|
-
if (verbose) {
|
|
354
|
-
console.warn('No API routes found')
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Process web routes
|
|
359
|
-
try {
|
|
360
|
-
const webRoutes = await import(webPath)
|
|
361
|
-
if (webRoutes.default) {
|
|
362
|
-
const routeDefs = Array.isArray(webRoutes.default) ? webRoutes.default : [webRoutes.default]
|
|
363
|
-
for (const route of routeDefs) {
|
|
364
|
-
const routeDoc: RouteDoc = {
|
|
365
|
-
path: route.path,
|
|
366
|
-
method: route.method,
|
|
367
|
-
middleware: Array.isArray(route.middleware)
|
|
368
|
-
? route.middleware.map((m: string | ((_request: Request) => Promise<Request | Response>)) =>
|
|
369
|
-
typeof m === 'string' ? m : 'function',
|
|
370
|
-
)
|
|
371
|
-
: undefined,
|
|
372
|
-
params: extractRouteParams(route.path),
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (typeof route.handler === 'string') {
|
|
376
|
-
const actionDocs = await loadActionDocs(route.handler)
|
|
377
|
-
Object.assign(routeDoc, actionDocs)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
routes.push(routeDoc)
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
catch {
|
|
385
|
-
if (verbose) {
|
|
386
|
-
console.warn('No web routes found')
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Generate and write markdown
|
|
391
|
-
const markdown = generateMarkdown(routes, { groupBy, includeExamples })
|
|
392
|
-
await Bun.write(output, markdown)
|
|
393
|
-
}
|
|
394
|
-
catch (error) {
|
|
395
|
-
throw new Error(`Failed to generate API documentation: ${error instanceof Error ? error.message : String(error)}`)
|
|
396
|
-
}
|
|
397
|
-
}
|