@stacksjs/bun-router 0.0.13 → 0.0.15
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/{chunk-1mvtv6jw.js → chunk-j0e7z7hd.js} +7549 -2508
- package/dist/cli.js +1023 -858
- package/dist/index.js +60 -25
- package/dist/response/macros.d.ts +19 -8
- package/dist/router/router.d.ts +39 -16
- package/dist/types.d.ts +12 -0
- package/package.json +3 -6
- package/src/middleware/auth.ts +2 -1
- package/src/middleware/file_upload.ts +11 -0
- package/src/response/macros.ts +65 -12
- package/src/router/file-based-routing.ts +20 -0
- package/src/router/file-streaming.ts +15 -4
- package/src/router/route-building.ts +29 -20
- package/src/router/router.ts +39 -16
- package/src/types.ts +12 -0
|
@@ -64,18 +64,26 @@ export function registerRouteBuilding(RouterClass: typeof Router): void {
|
|
|
64
64
|
matchPath(path, url.pathname, params, constraintsRecord)
|
|
65
65
|
const enhancedReq = this.enhanceRequest(req, params)
|
|
66
66
|
|
|
67
|
-
//
|
|
68
|
-
|
|
67
|
+
// Treat the route handler as the terminal middleware so the
|
|
68
|
+
// chain reaches it. Previously this code called
|
|
69
|
+
// `runMiddleware(stack)` without the handler and then only
|
|
70
|
+
// called `resolveHandler()` if middlewareResult was falsy.
|
|
71
|
+
// The chain in `buildMiddlewareChain` bottoms out in
|
|
72
|
+
// `return result || new Response(null, { status: 200 })` —
|
|
73
|
+
// so any user middleware that does `await next()` (cors,
|
|
74
|
+
// request-id, auth gates, etc.) gets a truthy empty Response
|
|
75
|
+
// back from the bottom of the chain, returns it, and the
|
|
76
|
+
// outer `if (middlewareResult)` short-circuits before the
|
|
77
|
+
// handler runs. Visible symptom: every route returns
|
|
78
|
+
// `200 OK` with `Content-Length: 0`.
|
|
79
|
+
const routeHandlerMiddleware = async (req2: any, _next: any) =>
|
|
80
|
+
await this.resolveHandler(route.handler, req2)
|
|
81
|
+
const middlewareStack = [...this.globalMiddleware, ...route.middleware, routeHandlerMiddleware]
|
|
82
|
+
const response = await this.runMiddleware(enhancedReq, middlewareStack)
|
|
83
|
+
return this.applyModifiedCookies(
|
|
84
|
+
response ?? new Response('No response from middleware chain', { status: 500 }),
|
|
69
85
|
enhancedReq,
|
|
70
|
-
[...this.globalMiddleware, ...route.middleware],
|
|
71
86
|
)
|
|
72
|
-
if (middlewareResult) {
|
|
73
|
-
return this.applyModifiedCookies(middlewareResult, enhancedReq)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Run route handler
|
|
77
|
-
const response = await this.resolveHandler(route.handler, enhancedReq)
|
|
78
|
-
return this.applyModifiedCookies(response, enhancedReq)
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
else {
|
|
@@ -95,18 +103,19 @@ export function registerRouteBuilding(RouterClass: typeof Router): void {
|
|
|
95
103
|
matchPath(path, url.pathname, params, constraintsRecord)
|
|
96
104
|
const enhancedReq = this.enhanceRequest(req, params)
|
|
97
105
|
|
|
98
|
-
//
|
|
99
|
-
|
|
106
|
+
// See the long comment above the single-method branch:
|
|
107
|
+
// include the route handler as the terminal middleware so
|
|
108
|
+
// the chain reaches it. Without this, any user middleware
|
|
109
|
+
// (cors, request-id) short-circuits to a 200-empty default
|
|
110
|
+
// and the handler never runs.
|
|
111
|
+
const routeHandlerMiddleware = async (req2: any, _next: any) =>
|
|
112
|
+
await this.resolveHandler(route.handler, req2)
|
|
113
|
+
const middlewareStack = [...this.globalMiddleware, ...route.middleware, routeHandlerMiddleware]
|
|
114
|
+
const response = await this.runMiddleware(enhancedReq, middlewareStack)
|
|
115
|
+
return this.applyModifiedCookies(
|
|
116
|
+
response ?? new Response('No response from middleware chain', { status: 500 }),
|
|
100
117
|
enhancedReq,
|
|
101
|
-
[...this.globalMiddleware, ...route.middleware],
|
|
102
118
|
)
|
|
103
|
-
if (middlewareResult) {
|
|
104
|
-
return this.applyModifiedCookies(middlewareResult, enhancedReq)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Run route handler
|
|
108
|
-
const response = await this.resolveHandler(route.handler, enhancedReq)
|
|
109
|
-
return this.applyModifiedCookies(response, enhancedReq)
|
|
110
119
|
}
|
|
111
120
|
}
|
|
112
121
|
|
package/src/router/router.ts
CHANGED
|
@@ -389,51 +389,73 @@ export class Router {
|
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
/**
|
|
392
|
-
* HTTP GET method
|
|
392
|
+
* HTTP GET method.
|
|
393
|
+
*
|
|
394
|
+
* `TPath` is inferred from the path literal at the call site, so an
|
|
395
|
+
* inline handler's `request.params` narrows to the extracted keyset:
|
|
396
|
+
*
|
|
397
|
+
* ```ts
|
|
398
|
+
* router.get('/api/users/{id}', (req) => {
|
|
399
|
+
* req.params.id // typed `string`, no `as any`
|
|
400
|
+
* // @ts-expect-error wrong key
|
|
401
|
+
* req.params.bogus
|
|
402
|
+
* })
|
|
403
|
+
* ```
|
|
404
|
+
*
|
|
405
|
+
* The string-action / class-handler forms (`'Actions/Foo/BarAction'`)
|
|
406
|
+
* keep working — `ActionHandler<TPath>` is a union that accepts them.
|
|
407
|
+
* See stacksjs/stacks#1851 for the broader typed-request work.
|
|
393
408
|
*/
|
|
394
|
-
get(path:
|
|
409
|
+
get<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
395
410
|
return this.registerRoute('GET', path, handler, type, name, middleware)
|
|
396
411
|
}
|
|
397
412
|
|
|
398
413
|
/**
|
|
399
|
-
* HTTP POST method
|
|
414
|
+
* HTTP POST method. See {@link get} for `TPath`-driven param
|
|
415
|
+
* narrowing on inline handlers.
|
|
400
416
|
*/
|
|
401
|
-
post(path:
|
|
417
|
+
post<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
402
418
|
return this.registerRoute('POST', path, handler, type, name, middleware)
|
|
403
419
|
}
|
|
404
420
|
|
|
405
421
|
/**
|
|
406
|
-
* HTTP PUT method
|
|
422
|
+
* HTTP PUT method. See {@link get} for `TPath`-driven param
|
|
423
|
+
* narrowing on inline handlers.
|
|
407
424
|
*/
|
|
408
|
-
put(path:
|
|
425
|
+
put<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
409
426
|
return this.registerRoute('PUT', path, handler, type, name, middleware)
|
|
410
427
|
}
|
|
411
428
|
|
|
412
429
|
/**
|
|
413
|
-
* HTTP PATCH method
|
|
430
|
+
* HTTP PATCH method. See {@link get} for `TPath`-driven param
|
|
431
|
+
* narrowing on inline handlers.
|
|
414
432
|
*/
|
|
415
|
-
patch(path:
|
|
433
|
+
patch<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
416
434
|
return this.registerRoute('PATCH', path, handler, type, name, middleware)
|
|
417
435
|
}
|
|
418
436
|
|
|
419
437
|
/**
|
|
420
|
-
* HTTP DELETE method
|
|
438
|
+
* HTTP DELETE method. See {@link get} for `TPath`-driven param
|
|
439
|
+
* narrowing on inline handlers.
|
|
421
440
|
*/
|
|
422
|
-
delete(path:
|
|
441
|
+
delete<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
423
442
|
return this.registerRoute('DELETE', path, handler, type, name, middleware)
|
|
424
443
|
}
|
|
425
444
|
|
|
426
445
|
/**
|
|
427
|
-
* HTTP OPTIONS method
|
|
446
|
+
* HTTP OPTIONS method. See {@link get} for `TPath`-driven param
|
|
447
|
+
* narrowing on inline handlers.
|
|
428
448
|
*/
|
|
429
|
-
options(path:
|
|
449
|
+
options<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
430
450
|
return this.registerRoute('OPTIONS', path, handler, type, name, middleware)
|
|
431
451
|
}
|
|
432
452
|
|
|
433
453
|
/**
|
|
434
|
-
* Register
|
|
454
|
+
* Register the same handler against multiple HTTP methods. The
|
|
455
|
+
* handler is type-narrowed via {@link ActionHandler}'s `TPath`
|
|
456
|
+
* generic, same as the single-method overloads.
|
|
435
457
|
*/
|
|
436
|
-
match(methods: string[], path:
|
|
458
|
+
match<TPath extends string>(methods: string[], path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
437
459
|
for (const method of methods) {
|
|
438
460
|
this.registerRoute(method, path, handler, type, name, middleware)
|
|
439
461
|
}
|
|
@@ -441,9 +463,10 @@ export class Router {
|
|
|
441
463
|
}
|
|
442
464
|
|
|
443
465
|
/**
|
|
444
|
-
* Register
|
|
466
|
+
* Register the handler against every HTTP method. See {@link get}
|
|
467
|
+
* for `TPath`-driven param narrowing on inline handlers.
|
|
445
468
|
*/
|
|
446
|
-
any(path:
|
|
469
|
+
any<TPath extends string>(path: TPath, handler: ActionHandler<TPath>, type?: 'api' | 'web', name?: string, middleware?: (string | MiddlewareHandler)[]): Router {
|
|
447
470
|
const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']
|
|
448
471
|
return this.match(methods, path, handler, type, name, middleware)
|
|
449
472
|
}
|
package/src/types.ts
CHANGED
|
@@ -1959,6 +1959,18 @@ export interface RequestMacroMethods {
|
|
|
1959
1959
|
cookies: () => Record<string, string>
|
|
1960
1960
|
|
|
1961
1961
|
// Files
|
|
1962
|
+
/**
|
|
1963
|
+
* Lookup a single uploaded file by form field name. Returns the
|
|
1964
|
+
* matching `FileInfo` (structurally an `UploadedFile`) or `null` when
|
|
1965
|
+
* no field with that name was uploaded. Populated by the multipart
|
|
1966
|
+
* file-upload middleware alongside `files: UploadedFile[]`. Mirrors
|
|
1967
|
+
* Laravel's `$request->file('avatar')`:
|
|
1968
|
+
*
|
|
1969
|
+
* ```ts
|
|
1970
|
+
* const avatar = req.file('avatar')
|
|
1971
|
+
* if (!avatar) return new Response('Missing avatar', { status: 400 })
|
|
1972
|
+
* ```
|
|
1973
|
+
*/
|
|
1962
1974
|
file: (name: string) => FileInfo | null
|
|
1963
1975
|
hasFile: (name: string) => boolean
|
|
1964
1976
|
|