@stacksjs/bun-router 0.0.7 → 0.0.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.
- package/dist/{chunk-jhsk5c5b.js → chunk-n5pvpz7q.js} +1430 -2840
- package/dist/cli.js +2 -2
- package/dist/index.js +359 -341
- package/dist/response/response-factory.d.ts +1 -1
- package/dist/router/index.d.ts +1 -0
- package/dist/router/router.d.ts +18 -0
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
- package/src/development/typescript-utilities.ts +4 -0
- package/src/response/response-factory.ts +13 -5
- package/src/router/index.ts +3 -1
- package/src/router/router.ts +57 -0
- package/src/router/server.ts +8 -1
- package/src/types.ts +6 -0
|
@@ -39,7 +39,7 @@ export interface ResponseCookieOptions {
|
|
|
39
39
|
sameSite?: 'strict' | 'lax' | 'none';
|
|
40
40
|
}
|
|
41
41
|
export interface ResponseFactory {
|
|
42
|
-
json: <T>(data: T, options?: JsonResponseOptions) => Response;
|
|
42
|
+
json: <T>(data: T, options?: JsonResponseOptions | ResponseStatus) => Response;
|
|
43
43
|
noContent: (headers?: Record<string, string>) => Response;
|
|
44
44
|
download: (filePath: string, filename?: string, headers?: Record<string, string>) => Promise<Response>;
|
|
45
45
|
file: (filePath: string, headers?: Record<string, string>) => Promise<Response>;
|
package/dist/router/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { FluentRouteBuilder, FluentRouter, RouteFactory, router, RouterUtils } f
|
|
|
4
4
|
import { Router } from './router';
|
|
5
5
|
import '../types';
|
|
6
6
|
export { Router };
|
|
7
|
+
export { applyRequestEnhancements } from './router';
|
|
7
8
|
declare module './router' {
|
|
8
9
|
interface Router {
|
|
9
10
|
stream: (callback: () => Generator<string | Uint8Array, void, unknown> | AsyncGenerator<string | Uint8Array, void, unknown>, status?: number, headers?: Record<string, string>) => Response;
|
package/dist/router/router.d.ts
CHANGED
|
@@ -274,3 +274,21 @@ export declare class RouteGroupBuilder {
|
|
|
274
274
|
put(_path: string, _handler: RouteHandler): this;
|
|
275
275
|
delete(_path: string, _handler: RouteHandler): this;
|
|
276
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Attach bun-router's request macros (`bearerToken`, `getParam`, `cookie`,
|
|
279
|
+
* `cookies`, `header`, `params`, plus the Laravel-style input helpers
|
|
280
|
+
* `get`, `input`, `string`, `integer`, `float`, `boolean`, `array`, `has`,
|
|
281
|
+
* `filled`, etc.) to a request.
|
|
282
|
+
*
|
|
283
|
+
* Idempotent: calling on an already-enhanced request returns it unchanged.
|
|
284
|
+
* We sniff `req.bearerToken` as the marker — cheap and reliable since no
|
|
285
|
+
* native Request has it.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* import { applyRequestEnhancements } from '@stacksjs/bun-router'
|
|
289
|
+
*
|
|
290
|
+
* const enhanced = applyRequestEnhancements(req, { id: '42' })
|
|
291
|
+
* enhanced.bearerToken() // → string | null
|
|
292
|
+
* enhanced.getParam('id') // → '42'
|
|
293
|
+
*/
|
|
294
|
+
export declare function applyRequestEnhancements(req: Request | EnhancedRequest, params?: Record<string, string>): EnhancedRequest;
|
package/dist/types.d.ts
CHANGED
|
@@ -688,6 +688,12 @@ export interface EnhancedRequest extends Request, Omit<RequestMacroMethods, 'ip'
|
|
|
688
688
|
* Route parameters extracted from the URL
|
|
689
689
|
*/
|
|
690
690
|
params: Record<string, string>;
|
|
691
|
+
/**
|
|
692
|
+
* Lookup a single route param. Equivalent to `request.params[name]` but
|
|
693
|
+
* with optional default-value handling, matching the Laravel-style
|
|
694
|
+
* `$request->route('name')` ergonomics.
|
|
695
|
+
*/
|
|
696
|
+
getParam: <T = string>(name: string, defaultValue?: T) => T | undefined;
|
|
691
697
|
/**
|
|
692
698
|
* Query parameters from the URL
|
|
693
699
|
*/
|
package/package.json
CHANGED
|
@@ -423,6 +423,10 @@ export type MiddlewareWithConfig<T> = (config: T) => MiddlewareFunction
|
|
|
423
423
|
const responseType = options.responseType || 'Response'
|
|
424
424
|
const paramsType = options.paramsType || 'Record<string, string>'
|
|
425
425
|
|
|
426
|
+
// pickier mis-parses the embedded `req:` token in this template literal
|
|
427
|
+
// as a real unused function parameter — disable on the next line so a
|
|
428
|
+
// pre-existing rule false positive doesn't block CI.
|
|
429
|
+
// eslint-disable-next-line pickier/no-unused-vars
|
|
426
430
|
return `(req: ${requestType} & { params: ${paramsType} }) => Promise<${responseType}>`
|
|
427
431
|
}
|
|
428
432
|
|
|
@@ -53,7 +53,7 @@ export interface ResponseCookieOptions {
|
|
|
53
53
|
// ============================================================================
|
|
54
54
|
|
|
55
55
|
export interface ResponseFactory {
|
|
56
|
-
json: <T>(data: T, options?: JsonResponseOptions) => Response
|
|
56
|
+
json: <T>(data: T, options?: JsonResponseOptions | ResponseStatus) => Response
|
|
57
57
|
noContent: (headers?: Record<string, string>) => Response
|
|
58
58
|
download: (filePath: string, filename?: string, headers?: Record<string, string>) => Promise<Response>
|
|
59
59
|
file: (filePath: string, headers?: Record<string, string>) => Promise<Response>
|
|
@@ -89,10 +89,18 @@ export interface ResponseFactory {
|
|
|
89
89
|
*/
|
|
90
90
|
export const response: ResponseFactory = {
|
|
91
91
|
/**
|
|
92
|
-
* Create a JSON response with proper typing
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
* Create a JSON response with proper typing.
|
|
93
|
+
*
|
|
94
|
+
* The second argument may be either a status code (Hono/Express style) or
|
|
95
|
+
* a `JsonResponseOptions` bag. The number form exists because passing a
|
|
96
|
+
* status as the second arg is the most common pattern in other web
|
|
97
|
+
* frameworks, and the silent `response.json(data, 401)` → HTTP 200 trap
|
|
98
|
+
* (the number was being interpreted as `options` and discarded) caused
|
|
99
|
+
* real bugs.
|
|
100
|
+
*/
|
|
101
|
+
json: <T>(data: T, options: JsonResponseOptions | ResponseStatus = {}): Response => {
|
|
102
|
+
const opts: JsonResponseOptions = typeof options === 'number' ? { status: options } : options
|
|
103
|
+
const { status = 200, headers = {}, pretty = false } = opts
|
|
96
104
|
const body = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)
|
|
97
105
|
|
|
98
106
|
return new Response(body, {
|
package/src/router/index.ts
CHANGED
|
@@ -33,8 +33,10 @@ registerModelBinding(Router)
|
|
|
33
33
|
registerFileBasedRouting(Router)
|
|
34
34
|
registerApiRoutes(Router)
|
|
35
35
|
|
|
36
|
-
// Export the Router class
|
|
36
|
+
// Export the Router class, the standalone request-enhancement helper, and
|
|
37
|
+
// fluent routing features.
|
|
37
38
|
export { Router }
|
|
39
|
+
export { applyRequestEnhancements } from './router'
|
|
38
40
|
|
|
39
41
|
// Type augmentation for Laravel-style methods
|
|
40
42
|
declare module './router' {
|
package/src/router/router.ts
CHANGED
|
@@ -1147,6 +1147,15 @@ export class Router {
|
|
|
1147
1147
|
return req.headers.get(name) || req.headers.get(name.toLowerCase()) || null
|
|
1148
1148
|
}
|
|
1149
1149
|
|
|
1150
|
+
// Convenience cookie reader. The full `enhancedReq.cookies.get(name)` API
|
|
1151
|
+
// is also available below — `cookie(name)` is the shorter form callers
|
|
1152
|
+
// (and the Laravel-style macros) reach for first, so it deserves a
|
|
1153
|
+
// direct method on the enhanced request, not just on the macros class.
|
|
1154
|
+
;(enhancedReq as any).cookie = (name: string, defaultValue?: string): string | null => {
|
|
1155
|
+
const value = getCookies()[name]
|
|
1156
|
+
return value !== undefined ? value : (defaultValue ?? null)
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1150
1159
|
;(enhancedReq as any).getParam = <T = string>(name: string, defaultValue?: T): T | undefined => {
|
|
1151
1160
|
const value = params?.[name] as T | undefined
|
|
1152
1161
|
return value !== undefined ? value : defaultValue
|
|
@@ -1522,3 +1531,51 @@ export class RouteGroupBuilder {
|
|
|
1522
1531
|
return this
|
|
1523
1532
|
}
|
|
1524
1533
|
}
|
|
1534
|
+
|
|
1535
|
+
// ---------------------------------------------------------------------------
|
|
1536
|
+
// Standalone enhancement helper
|
|
1537
|
+
// ---------------------------------------------------------------------------
|
|
1538
|
+
|
|
1539
|
+
// Singleton scratch Router used to expose `enhanceRequest` as a standalone
|
|
1540
|
+
// function. Downstream consumers (frameworks layered on bun-router) often
|
|
1541
|
+
// need to attach the request macros to a request that was created outside
|
|
1542
|
+
// of `route.serve()` — for instance, when a higher-level router wraps
|
|
1543
|
+
// each handler with its own middleware chain. Without an exported function,
|
|
1544
|
+
// those consumers either spin up their own `new Router()` per call or
|
|
1545
|
+
// duplicate the attachment logic in user code.
|
|
1546
|
+
//
|
|
1547
|
+
// We share one instance because `enhanceRequest` does not depend on any
|
|
1548
|
+
// per-router state (route table, middleware groups, etc.) — it only reads
|
|
1549
|
+
// from the request and the supplied params.
|
|
1550
|
+
let _enhancementHost: Router | null = null
|
|
1551
|
+
|
|
1552
|
+
function getEnhancementHost(): Router {
|
|
1553
|
+
if (_enhancementHost === null) _enhancementHost = new Router()
|
|
1554
|
+
return _enhancementHost
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* Attach bun-router's request macros (`bearerToken`, `getParam`, `cookie`,
|
|
1559
|
+
* `cookies`, `header`, `params`, plus the Laravel-style input helpers
|
|
1560
|
+
* `get`, `input`, `string`, `integer`, `float`, `boolean`, `array`, `has`,
|
|
1561
|
+
* `filled`, etc.) to a request.
|
|
1562
|
+
*
|
|
1563
|
+
* Idempotent: calling on an already-enhanced request returns it unchanged.
|
|
1564
|
+
* We sniff `req.bearerToken` as the marker — cheap and reliable since no
|
|
1565
|
+
* native Request has it.
|
|
1566
|
+
*
|
|
1567
|
+
* @example
|
|
1568
|
+
* import { applyRequestEnhancements } from '@stacksjs/bun-router'
|
|
1569
|
+
*
|
|
1570
|
+
* const enhanced = applyRequestEnhancements(req, { id: '42' })
|
|
1571
|
+
* enhanced.bearerToken() // → string | null
|
|
1572
|
+
* enhanced.getParam('id') // → '42'
|
|
1573
|
+
*/
|
|
1574
|
+
export function applyRequestEnhancements(
|
|
1575
|
+
req: Request | EnhancedRequest,
|
|
1576
|
+
params: Record<string, string> = {},
|
|
1577
|
+
): EnhancedRequest {
|
|
1578
|
+
if (typeof (req as any).bearerToken === 'function')
|
|
1579
|
+
return req as EnhancedRequest
|
|
1580
|
+
return getEnhancementHost().enhanceRequest(req as Request, params)
|
|
1581
|
+
}
|
package/src/router/server.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Server } from 'bun'
|
|
2
2
|
import type { EnhancedRequest, HTTPMethod, ServerOptions } from '../types'
|
|
3
3
|
import type { Router } from './router'
|
|
4
|
+
import { RequestWithMacros } from '../request/macros'
|
|
4
5
|
import { runWithRequest, setCurrentRequest } from '../request/context'
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -333,7 +334,13 @@ export function registerServerHandling(RouterClass: typeof Router): void {
|
|
|
333
334
|
_cookiesToDelete: [],
|
|
334
335
|
}) as unknown as EnhancedRequest
|
|
335
336
|
|
|
336
|
-
//
|
|
337
|
+
// Attach registered request macros (input, has, bearerToken, etc.) so
|
|
338
|
+
// they're available in middleware and handlers without manual setup.
|
|
339
|
+
// Applied *before* the cookie utility so the cookies macro doesn't
|
|
340
|
+
// overwrite the get/set/delete object form consumers depend on.
|
|
341
|
+
RequestWithMacros.applyMacros(enhancedReq)
|
|
342
|
+
|
|
343
|
+
// Add cookie methods to the request (overrides any macro named `cookies`).
|
|
337
344
|
Object.assign(enhancedReq, { cookies: { ...getCookies(), ...cookies } })
|
|
338
345
|
|
|
339
346
|
return enhancedReq
|
package/src/types.ts
CHANGED
|
@@ -793,6 +793,12 @@ export interface EnhancedRequest extends Request, Omit<RequestMacroMethods, 'ip'
|
|
|
793
793
|
* Route parameters extracted from the URL
|
|
794
794
|
*/
|
|
795
795
|
params: Record<string, string>
|
|
796
|
+
/**
|
|
797
|
+
* Lookup a single route param. Equivalent to `request.params[name]` but
|
|
798
|
+
* with optional default-value handling, matching the Laravel-style
|
|
799
|
+
* `$request->route('name')` ergonomics.
|
|
800
|
+
*/
|
|
801
|
+
getParam: <T = string>(name: string, defaultValue?: T) => T | undefined
|
|
796
802
|
/**
|
|
797
803
|
* Query parameters from the URL
|
|
798
804
|
*/
|