@bunary/http 0.1.3 → 0.3.0
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/CHANGELOG.md +37 -0
- package/dist/app.d.ts +7 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/context.d.ts +13 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/cors.d.ts +82 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/handlers/methodNotAllowed.d.ts.map +1 -1
- package/dist/handlers/notFound.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +186 -31
- package/dist/router.d.ts +2 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/routes/find.d.ts +7 -0
- package/dist/routes/find.d.ts.map +1 -1
- package/dist/routes/group.d.ts.map +1 -1
- package/dist/routes/index.d.ts +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/types/appOptions.d.ts +6 -4
- package/dist/types/appOptions.d.ts.map +1 -1
- package/dist/types/bunaryApp.d.ts +19 -10
- package/dist/types/bunaryApp.d.ts.map +1 -1
- package/dist/types/groupOptions.d.ts +4 -2
- package/dist/types/groupOptions.d.ts.map +1 -1
- package/dist/types/groupRouter.d.ts +13 -8
- package/dist/types/groupRouter.d.ts.map +1 -1
- package/dist/types/middleware.d.ts +9 -4
- package/dist/types/middleware.d.ts.map +1 -1
- package/dist/types/requestContext.d.ts +72 -7
- package/dist/types/requestContext.d.ts.map +1 -1
- package/dist/types/route.d.ts +2 -0
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/routeBuilder.d.ts +11 -9
- package/dist/types/routeBuilder.d.ts.map +1 -1
- package/dist/types/routeHandler.d.ts +7 -3
- package/dist/types/routeHandler.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to `@bunary/http` will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.0] - 2026-02-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Built-in CORS middleware via `cors()` factory (#47)
|
|
13
|
+
- `cors()` with no arguments allows all origins (default `Access-Control-Allow-Origin: *`)
|
|
14
|
+
- Configurable `origin` (string, string array, or `"*"`), `methods`, `allowHeaders`, `exposeHeaders`, `credentials`, `maxAge`
|
|
15
|
+
- Handles preflight `OPTIONS` requests automatically — returns 204 with CORS headers
|
|
16
|
+
- Reflects `Access-Control-Request-Headers` by default, or uses explicit `allowHeaders`
|
|
17
|
+
- Adds `Vary: Origin` when origin is not `"*"` for correct cache behavior
|
|
18
|
+
- Works as global middleware (`app.use(cors())`) or per-group (`middleware: [cors()]`)
|
|
19
|
+
- `CorsOptions` type exported for TypeScript consumers
|
|
20
|
+
|
|
21
|
+
- Body parsing helpers on `RequestContext` — `ctx.json()`, `ctx.text()`, `ctx.formData()` (#51)
|
|
22
|
+
- `ctx.json<T>()` — parse JSON body with type inference, throws `BodyParseError` on malformed input
|
|
23
|
+
- `ctx.text()` — get request body as string
|
|
24
|
+
- `ctx.formData()` — parse multipart/URL-encoded form data, throws `BodyParseError` on malformed input
|
|
25
|
+
- `BodyParseError` class exported for catch-based error handling in handlers
|
|
26
|
+
- Thin wrappers around `Request` methods — no parsing framework, no validation, zero new dependencies
|
|
27
|
+
|
|
28
|
+
## [0.2.0] - 2026-02-15
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Typed `ctx.locals` via `createApp<TLocals>()` generic (#43)
|
|
33
|
+
- `RequestContext<TLocals, TParams>` now accepts two type parameters with backward-compatible defaults
|
|
34
|
+
- `createApp<{ user: User }>()` propagates `TLocals` to all handlers, middleware, groups, and options callbacks
|
|
35
|
+
- `Middleware<TLocals>`, `BunaryApp<TLocals>`, `GroupRouter<TLocals>`, `GroupOptions<TLocals>`, `AppOptions<TLocals>` all generic
|
|
36
|
+
- Fully backward-compatible — omitting the generic keeps the existing `Record<string, unknown>` behaviour
|
|
37
|
+
|
|
38
|
+
- Typed route parameters via per-route `<TParams>` generic (#50)
|
|
39
|
+
- `app.get<{ id: string }>("/users/:id", handler)` narrows `ctx.params` to `{ id: string }` inside the handler
|
|
40
|
+
- Works on all HTTP methods: `get`, `post`, `put`, `patch`, `delete`
|
|
41
|
+
- Works inside route groups: `router.get<{ id: string }>(...)`
|
|
42
|
+
- Values remain strings at runtime — the generic only narrows the TypeScript type
|
|
43
|
+
- Default `PathParams` (`Record<string, string | undefined>`) preserved when no generic is provided
|
|
44
|
+
|
|
8
45
|
## [0.1.3] - 2026-02-15
|
|
9
46
|
|
|
10
47
|
### Fixed
|
package/dist/app.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ import type { AppOptions, BunaryApp } from "./types/index.js";
|
|
|
35
35
|
*
|
|
36
36
|
* @param options - Optional configuration
|
|
37
37
|
* @param options.basePath - Base path prefix for all routes (e.g., "/api")
|
|
38
|
+
* @typeParam TLocals — Shape of `ctx.locals`. Defaults to `Record<string, unknown>`.
|
|
38
39
|
* @returns BunaryApp instance
|
|
39
40
|
*
|
|
40
41
|
* @example
|
|
@@ -46,7 +47,12 @@ import type { AppOptions, BunaryApp } from "./types/index.js";
|
|
|
46
47
|
* // With basePath
|
|
47
48
|
* const apiApp = createApp({ basePath: "/api" });
|
|
48
49
|
* apiApp.get("/users", () => ({})); // Matches /api/users
|
|
50
|
+
*
|
|
51
|
+
* // With typed locals
|
|
52
|
+
* interface Locals { user: User; requestId: string }
|
|
53
|
+
* const typedApp = createApp<Locals>();
|
|
54
|
+
* typedApp.get("/me", (ctx) => ({ user: ctx.locals.user })); // typed
|
|
49
55
|
* ```
|
|
50
56
|
*/
|
|
51
|
-
export declare function createApp(options?: AppOptions): BunaryApp
|
|
57
|
+
export declare function createApp<TLocals extends object = Record<string, unknown>>(options?: AppOptions<TLocals>): BunaryApp<TLocals>;
|
|
52
58
|
//# sourceMappingURL=app.d.ts.map
|
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACX,UAAU,EACV,SAAS,EAYT,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAgB,SAAS,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAC3B,SAAS,CAAC,OAAO,CAAC,CAkSpB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PathParams } from "./types/pathParams.js";
|
|
2
|
+
import type { RequestContext } from "./types/requestContext.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create a RequestContext for a given request and params.
|
|
5
|
+
*
|
|
6
|
+
* Centralises context construction so that body helpers (`json`, `text`,
|
|
7
|
+
* `formData`) are available everywhere a `RequestContext` is built —
|
|
8
|
+
* including 404/405 handler contexts.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function createRequestContext(request: Request, params: PathParams, query: URLSearchParams): RequestContext;
|
|
13
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,eAAe,GACpB,cAAc,CAsBhB"}
|
package/dist/cors.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Middleware } from "./types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* CORS configuration options.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const options: CorsOptions = {
|
|
8
|
+
* origin: "https://myapp.com",
|
|
9
|
+
* methods: ["GET", "POST"],
|
|
10
|
+
* credentials: true,
|
|
11
|
+
* maxAge: 86400,
|
|
12
|
+
* };
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export interface CorsOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Allowed origin(s). Use `"*"` (default) for any origin,
|
|
18
|
+
* a single string for one origin, or an array for multiple.
|
|
19
|
+
*
|
|
20
|
+
* @default "*"
|
|
21
|
+
*/
|
|
22
|
+
origin?: string | string[];
|
|
23
|
+
/**
|
|
24
|
+
* HTTP methods to advertise in `Access-Control-Allow-Methods`.
|
|
25
|
+
*
|
|
26
|
+
* @default ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"]
|
|
27
|
+
*/
|
|
28
|
+
methods?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Headers the client is allowed to send.
|
|
31
|
+
* When omitted, the value of `Access-Control-Request-Headers` is reflected.
|
|
32
|
+
*/
|
|
33
|
+
allowHeaders?: string[];
|
|
34
|
+
/**
|
|
35
|
+
* Response headers the browser may expose to client-side JavaScript.
|
|
36
|
+
*/
|
|
37
|
+
exposeHeaders?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Whether to include `Access-Control-Allow-Credentials: true`.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
credentials?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* How long (in seconds) the browser may cache preflight results.
|
|
46
|
+
* Omitted from the response when `undefined`.
|
|
47
|
+
*/
|
|
48
|
+
maxAge?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a CORS middleware.
|
|
52
|
+
*
|
|
53
|
+
* Handles preflight `OPTIONS` requests (returns 204) and
|
|
54
|
+
* adds CORS headers to actual responses.
|
|
55
|
+
*
|
|
56
|
+
* @param options - CORS configuration (defaults allow all origins)
|
|
57
|
+
* @returns Middleware function
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { createApp, cors } from "@bunary/http";
|
|
62
|
+
*
|
|
63
|
+
* // Allow any origin
|
|
64
|
+
* const app = createApp();
|
|
65
|
+
* app.use(cors());
|
|
66
|
+
*
|
|
67
|
+
* // Restrict to a single origin with credentials
|
|
68
|
+
* app.use(cors({
|
|
69
|
+
* origin: "https://myapp.com",
|
|
70
|
+
* credentials: true,
|
|
71
|
+
* maxAge: 86400,
|
|
72
|
+
* }));
|
|
73
|
+
*
|
|
74
|
+
* // Multiple allowed origins
|
|
75
|
+
* app.use(cors({
|
|
76
|
+
* origin: ["https://app1.com", "https://app2.com"],
|
|
77
|
+
* methods: ["GET", "POST"],
|
|
78
|
+
* }));
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function cors(options?: CorsOptions): Middleware;
|
|
82
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CAwF1D"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when request body parsing fails.
|
|
3
|
+
*
|
|
4
|
+
* Thrown by `ctx.json()` and `ctx.formData()` when the request body
|
|
5
|
+
* cannot be parsed. Handlers can catch this to return a custom 400 response.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { BodyParseError } from "@bunary/http";
|
|
10
|
+
*
|
|
11
|
+
* app.post("/users", async (ctx) => {
|
|
12
|
+
* try {
|
|
13
|
+
* const body = await ctx.json();
|
|
14
|
+
* return { received: body };
|
|
15
|
+
* } catch (error) {
|
|
16
|
+
* if (error instanceof BodyParseError) {
|
|
17
|
+
* return new Response(JSON.stringify({ error: error.message }), {
|
|
18
|
+
* status: 400,
|
|
19
|
+
* headers: { "Content-Type": "application/json" },
|
|
20
|
+
* });
|
|
21
|
+
* }
|
|
22
|
+
* throw error;
|
|
23
|
+
* }
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class BodyParseError extends Error {
|
|
28
|
+
readonly name = "BodyParseError";
|
|
29
|
+
/** The underlying parse error, if available */
|
|
30
|
+
readonly cause?: unknown;
|
|
31
|
+
constructor(message: string, cause?: unknown);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACxC,SAAkB,IAAI,oBAAoB;IAE1C,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAI5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"methodNotAllowed.d.ts","sourceRoot":"","sources":["../../src/handlers/methodNotAllowed.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"methodNotAllowed.d.ts","sourceRoot":"","sources":["../../src/handlers/methodNotAllowed.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAkB,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE3E;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,CAAC,EAAE,UAAU,EACpB,WAAW,CAAC,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,QAAQ,CAAC,CA2BnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notFound.d.ts","sourceRoot":"","sources":["../../src/handlers/notFound.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"notFound.d.ts","sourceRoot":"","sources":["../../src/handlers/notFound.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAEpE;;;GAGG;AACH,wBAAsB,cAAc,CACnC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,QAAQ,CAAC,CAWnB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,5 +19,8 @@
|
|
|
19
19
|
* @packageDocumentation
|
|
20
20
|
*/
|
|
21
21
|
export { createApp } from "./app.js";
|
|
22
|
+
export type { CorsOptions } from "./cors.js";
|
|
23
|
+
export { cors } from "./cors.js";
|
|
24
|
+
export { BodyParseError } from "./errors.js";
|
|
22
25
|
export type { AppOptions, BunaryApp, BunaryServer, GroupCallback, GroupOptions, GroupRouter, HandlerResponse, HttpMethod, ListenOptions, Middleware, PathParams, RequestContext, RouteBuilder, RouteHandler, RouteInfo, } from "./types/index.js";
|
|
23
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,YAAY,EACX,UAAU,EACV,SAAS,EACT,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,UAAU,EACV,aAAa,EACb,UAAU,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,GACT,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// src/errors.ts
|
|
3
|
+
class BodyParseError extends Error {
|
|
4
|
+
name = "BodyParseError";
|
|
5
|
+
cause;
|
|
6
|
+
constructor(message, cause) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.cause = cause;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/context.ts
|
|
13
|
+
function createRequestContext(request, params, query) {
|
|
14
|
+
return {
|
|
15
|
+
request,
|
|
16
|
+
params,
|
|
17
|
+
query,
|
|
18
|
+
locals: {},
|
|
19
|
+
json: async () => {
|
|
20
|
+
try {
|
|
21
|
+
return await request.json();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new BodyParseError("Failed to parse JSON body", error);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
text: () => request.text(),
|
|
27
|
+
formData: async () => {
|
|
28
|
+
try {
|
|
29
|
+
return await request.formData();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new BodyParseError("Failed to parse form data", error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
2
37
|
// src/response.ts
|
|
3
38
|
function toResponse(result) {
|
|
4
39
|
if (result instanceof Response) {
|
|
@@ -163,7 +198,19 @@ function wrapBuilderWithNamePrefix(builder, namePrefix) {
|
|
|
163
198
|
function compilePath(path) {
|
|
164
199
|
const paramNames = [];
|
|
165
200
|
const optionalParams = [];
|
|
166
|
-
let
|
|
201
|
+
let isWildcard = false;
|
|
202
|
+
let processedPath = path;
|
|
203
|
+
if (processedPath.endsWith("/**")) {
|
|
204
|
+
processedPath = processedPath.slice(0, -3);
|
|
205
|
+
isWildcard = true;
|
|
206
|
+
} else if (processedPath.endsWith("/*")) {
|
|
207
|
+
processedPath = processedPath.slice(0, -2);
|
|
208
|
+
isWildcard = true;
|
|
209
|
+
}
|
|
210
|
+
if (processedPath.includes("*")) {
|
|
211
|
+
throw new Error(`Wildcard "*" must appear at the end of the route pattern "${path}". Mid-path wildcards are not supported.`);
|
|
212
|
+
}
|
|
213
|
+
let regexString = processedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
167
214
|
regexString = regexString.replace(/\/:([a-zA-Z_][a-zA-Z0-9_]*)(\\\?)?/g, (_match, paramName, isOptional) => {
|
|
168
215
|
if (paramNames.includes(paramName)) {
|
|
169
216
|
throw new Error(`Duplicate parameter name ":${paramName}" in route pattern "${path}". Each parameter name must be unique within a route.`);
|
|
@@ -175,11 +222,17 @@ function compilePath(path) {
|
|
|
175
222
|
}
|
|
176
223
|
return "/([^/]+)";
|
|
177
224
|
});
|
|
178
|
-
|
|
225
|
+
if (isWildcard) {
|
|
226
|
+
regexString += "(?:/(.*))?";
|
|
227
|
+
paramNames.push("*");
|
|
228
|
+
} else {
|
|
229
|
+
regexString += "/?";
|
|
230
|
+
}
|
|
179
231
|
return {
|
|
180
232
|
pattern: new RegExp(`^${regexString}$`),
|
|
181
233
|
paramNames,
|
|
182
|
-
optionalParams
|
|
234
|
+
optionalParams,
|
|
235
|
+
isWildcard
|
|
183
236
|
};
|
|
184
237
|
}
|
|
185
238
|
function safeDecodeURIComponent(value) {
|
|
@@ -241,6 +294,17 @@ function resolveRoute(routes, method, path) {
|
|
|
241
294
|
allowedMethods: Array.from(allowedMethods).sort()
|
|
242
295
|
};
|
|
243
296
|
}
|
|
297
|
+
function findRouteByPath(routes, path) {
|
|
298
|
+
for (const route of routes) {
|
|
299
|
+
if (!route.pattern.test(path))
|
|
300
|
+
continue;
|
|
301
|
+
const params = extractParams(path, route);
|
|
302
|
+
if (!checkConstraints(params, route.constraints))
|
|
303
|
+
continue;
|
|
304
|
+
return { route, params };
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
244
308
|
function getAllowedMethods(routes, path) {
|
|
245
309
|
const methods = new Set;
|
|
246
310
|
for (const route of routes) {
|
|
@@ -327,12 +391,7 @@ function toHeadResponse(response) {
|
|
|
327
391
|
async function handleMethodNotAllowed(request, path, routes, options, precomputed) {
|
|
328
392
|
const url = new URL(request.url);
|
|
329
393
|
const allowedMethods = precomputed ?? getAllowedMethods(routes, path);
|
|
330
|
-
const methodNotAllowedCtx = {
|
|
331
|
-
request,
|
|
332
|
-
params: {},
|
|
333
|
-
query: url.searchParams,
|
|
334
|
-
locals: {}
|
|
335
|
-
};
|
|
394
|
+
const methodNotAllowedCtx = createRequestContext(request, {}, url.searchParams);
|
|
336
395
|
if (options?.onMethodNotAllowed) {
|
|
337
396
|
const result = await options.onMethodNotAllowed(methodNotAllowedCtx, allowedMethods);
|
|
338
397
|
const response = toResponse(result);
|
|
@@ -359,12 +418,7 @@ async function handleMethodNotAllowed(request, path, routes, options, precompute
|
|
|
359
418
|
// src/handlers/notFound.ts
|
|
360
419
|
async function handleNotFound(request, _path, options) {
|
|
361
420
|
const url = new URL(request.url);
|
|
362
|
-
const notFoundCtx = {
|
|
363
|
-
request,
|
|
364
|
-
params: {},
|
|
365
|
-
query: url.searchParams,
|
|
366
|
-
locals: {}
|
|
367
|
-
};
|
|
421
|
+
const notFoundCtx = createRequestContext(request, {}, url.searchParams);
|
|
368
422
|
if (options?.onNotFound) {
|
|
369
423
|
const result = await options.onNotFound(notFoundCtx);
|
|
370
424
|
return toResponse(result);
|
|
@@ -401,10 +455,11 @@ async function executeRoute(match, ctx, getMiddlewareChain) {
|
|
|
401
455
|
}
|
|
402
456
|
// src/app.ts
|
|
403
457
|
function createApp(options) {
|
|
458
|
+
const internalOpts = options;
|
|
404
459
|
const routes = [];
|
|
405
460
|
const middlewares = [];
|
|
406
461
|
const namedRoutes = new Map;
|
|
407
|
-
const normalizedBasePath =
|
|
462
|
+
const normalizedBasePath = internalOpts?.basePath ? normalizePrefix(internalOpts.basePath) : "";
|
|
408
463
|
const basePath = normalizedBasePath === "/" ? "" : normalizedBasePath;
|
|
409
464
|
let globalMiddlewareVersion = 0;
|
|
410
465
|
const middlewareCache = new WeakMap;
|
|
@@ -419,7 +474,7 @@ function createApp(options) {
|
|
|
419
474
|
}
|
|
420
475
|
function addRoute(method, path, handler, groupMiddleware = []) {
|
|
421
476
|
const fullPath = basePath ? joinPaths(basePath, path) : path;
|
|
422
|
-
const { pattern, paramNames, optionalParams } = compilePath(fullPath);
|
|
477
|
+
const { pattern, paramNames, optionalParams, isWildcard } = compilePath(fullPath);
|
|
423
478
|
const route = {
|
|
424
479
|
method,
|
|
425
480
|
path: fullPath,
|
|
@@ -427,7 +482,8 @@ function createApp(options) {
|
|
|
427
482
|
paramNames,
|
|
428
483
|
handler,
|
|
429
484
|
optionalParams: optionalParams.length > 0 ? optionalParams : undefined,
|
|
430
|
-
middleware: groupMiddleware.length > 0 ? [...groupMiddleware] : undefined
|
|
485
|
+
middleware: groupMiddleware.length > 0 ? [...groupMiddleware] : undefined,
|
|
486
|
+
isWildcard: isWildcard || undefined
|
|
431
487
|
};
|
|
432
488
|
routes.push(route);
|
|
433
489
|
return createRouteBuilder(route, namedRoutes, app);
|
|
@@ -437,21 +493,34 @@ function createApp(options) {
|
|
|
437
493
|
const path = url.pathname;
|
|
438
494
|
const method = request.method;
|
|
439
495
|
if (method === "OPTIONS") {
|
|
440
|
-
|
|
496
|
+
if (request.headers.get("Origin")) {
|
|
497
|
+
const routeMatch = findRouteByPath(routes, path);
|
|
498
|
+
const chain = routeMatch ? getMiddlewareChain(routeMatch.route) : middlewares.length > 0 ? [...middlewares] : [];
|
|
499
|
+
if (chain.length > 0) {
|
|
500
|
+
const params = routeMatch?.params ?? {};
|
|
501
|
+
const ctx2 = createRequestContext(request, params, url.searchParams);
|
|
502
|
+
let index = 0;
|
|
503
|
+
const next = async () => {
|
|
504
|
+
if (index < chain.length) {
|
|
505
|
+
const mw = chain[index++];
|
|
506
|
+
return await mw(ctx2, next);
|
|
507
|
+
}
|
|
508
|
+
return await handleOptions(request, path, routes, internalOpts);
|
|
509
|
+
};
|
|
510
|
+
const result = await next();
|
|
511
|
+
return toResponse(result);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return await handleOptions(request, path, routes, internalOpts);
|
|
441
515
|
}
|
|
442
516
|
const { match, allowedMethods } = resolveRoute(routes, method, path);
|
|
443
517
|
if (!match) {
|
|
444
518
|
if (allowedMethods.length > 0) {
|
|
445
|
-
return await handleMethodNotAllowed(request, path, routes,
|
|
519
|
+
return await handleMethodNotAllowed(request, path, routes, internalOpts, allowedMethods);
|
|
446
520
|
}
|
|
447
|
-
return await handleNotFound(request, path,
|
|
521
|
+
return await handleNotFound(request, path, internalOpts);
|
|
448
522
|
}
|
|
449
|
-
const ctx =
|
|
450
|
-
request,
|
|
451
|
-
params: match.params,
|
|
452
|
-
query: url.searchParams,
|
|
453
|
-
locals: {}
|
|
454
|
-
};
|
|
523
|
+
const ctx = createRequestContext(request, match.params, url.searchParams);
|
|
455
524
|
try {
|
|
456
525
|
const response = await executeRoute(match, ctx, getMiddlewareChain);
|
|
457
526
|
if (method === "HEAD") {
|
|
@@ -459,7 +528,7 @@ function createApp(options) {
|
|
|
459
528
|
}
|
|
460
529
|
return response;
|
|
461
530
|
} catch (error) {
|
|
462
|
-
return await handleError(ctx, error,
|
|
531
|
+
return await handleError(ctx, error, internalOpts);
|
|
463
532
|
}
|
|
464
533
|
}
|
|
465
534
|
const app = {
|
|
@@ -474,8 +543,8 @@ function createApp(options) {
|
|
|
474
543
|
return app;
|
|
475
544
|
},
|
|
476
545
|
group: (prefixOrOptions, callback) => {
|
|
477
|
-
const
|
|
478
|
-
const groupRouter = createGroupRouter(
|
|
546
|
+
const groupOpts = typeof prefixOrOptions === "string" ? { prefix: prefixOrOptions } : prefixOrOptions;
|
|
547
|
+
const groupRouter = createGroupRouter(groupOpts.prefix, groupOpts.middleware ?? [], groupOpts.name ?? "", addRoute);
|
|
479
548
|
callback(groupRouter);
|
|
480
549
|
return app;
|
|
481
550
|
},
|
|
@@ -497,6 +566,17 @@ function createApp(options) {
|
|
|
497
566
|
const queryParams = {};
|
|
498
567
|
const usedParams = new Set;
|
|
499
568
|
for (const paramName of route.paramNames) {
|
|
569
|
+
if (paramName === "*") {
|
|
570
|
+
const wildcardValue = params?.["*"];
|
|
571
|
+
if (wildcardValue !== undefined) {
|
|
572
|
+
const encoded = String(wildcardValue).split("/").map(encodeURIComponent).join("/");
|
|
573
|
+
url = url.replace(/\/\*{1,2}$/, `/${encoded}`);
|
|
574
|
+
usedParams.add("*");
|
|
575
|
+
} else {
|
|
576
|
+
url = url.replace(/\/\*{1,2}$/, "");
|
|
577
|
+
}
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
500
580
|
const isOptional = route.optionalParams?.includes(paramName);
|
|
501
581
|
const value = params?.[paramName];
|
|
502
582
|
if (value !== undefined) {
|
|
@@ -558,6 +638,81 @@ function createApp(options) {
|
|
|
558
638
|
};
|
|
559
639
|
return app;
|
|
560
640
|
}
|
|
641
|
+
// src/cors.ts
|
|
642
|
+
var DEFAULT_METHODS = ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"];
|
|
643
|
+
function resolveOrigin(allowed, requestOrigin, credentials) {
|
|
644
|
+
if (allowed === "*") {
|
|
645
|
+
return credentials ? requestOrigin : "*";
|
|
646
|
+
}
|
|
647
|
+
if (typeof allowed === "string") {
|
|
648
|
+
return allowed === requestOrigin ? allowed : null;
|
|
649
|
+
}
|
|
650
|
+
return allowed.includes(requestOrigin) ? requestOrigin : null;
|
|
651
|
+
}
|
|
652
|
+
function cors(options = {}) {
|
|
653
|
+
const {
|
|
654
|
+
origin = "*",
|
|
655
|
+
methods = DEFAULT_METHODS,
|
|
656
|
+
allowHeaders,
|
|
657
|
+
exposeHeaders,
|
|
658
|
+
credentials = false,
|
|
659
|
+
maxAge
|
|
660
|
+
} = options;
|
|
661
|
+
return async (ctx, next) => {
|
|
662
|
+
const requestOrigin = ctx.request.headers.get("Origin");
|
|
663
|
+
if (!requestOrigin) {
|
|
664
|
+
return await next();
|
|
665
|
+
}
|
|
666
|
+
const allowedOrigin = resolveOrigin(origin, requestOrigin, credentials);
|
|
667
|
+
if (!allowedOrigin) {
|
|
668
|
+
return await next();
|
|
669
|
+
}
|
|
670
|
+
const needsVary = origin !== "*" || credentials;
|
|
671
|
+
if (ctx.request.method === "OPTIONS") {
|
|
672
|
+
const headers = new Headers;
|
|
673
|
+
headers.set("Access-Control-Allow-Origin", allowedOrigin);
|
|
674
|
+
if (needsVary) {
|
|
675
|
+
headers.append("Vary", "Origin");
|
|
676
|
+
}
|
|
677
|
+
headers.set("Access-Control-Allow-Methods", methods.join(", "));
|
|
678
|
+
if (allowHeaders) {
|
|
679
|
+
headers.set("Access-Control-Allow-Headers", allowHeaders.join(", "));
|
|
680
|
+
} else {
|
|
681
|
+
const requested = ctx.request.headers.get("Access-Control-Request-Headers");
|
|
682
|
+
if (requested) {
|
|
683
|
+
headers.set("Access-Control-Allow-Headers", requested);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (credentials) {
|
|
687
|
+
headers.set("Access-Control-Allow-Credentials", "true");
|
|
688
|
+
}
|
|
689
|
+
if (maxAge !== undefined) {
|
|
690
|
+
headers.set("Access-Control-Max-Age", String(maxAge));
|
|
691
|
+
}
|
|
692
|
+
return new Response(null, { status: 204, headers });
|
|
693
|
+
}
|
|
694
|
+
const result = await next();
|
|
695
|
+
const response = toResponse(result);
|
|
696
|
+
const newHeaders = new Headers(response.headers);
|
|
697
|
+
newHeaders.set("Access-Control-Allow-Origin", allowedOrigin);
|
|
698
|
+
if (needsVary) {
|
|
699
|
+
newHeaders.append("Vary", "Origin");
|
|
700
|
+
}
|
|
701
|
+
if (exposeHeaders && exposeHeaders.length > 0) {
|
|
702
|
+
newHeaders.set("Access-Control-Expose-Headers", exposeHeaders.join(", "));
|
|
703
|
+
}
|
|
704
|
+
if (credentials) {
|
|
705
|
+
newHeaders.set("Access-Control-Allow-Credentials", "true");
|
|
706
|
+
}
|
|
707
|
+
return new Response(response.body, {
|
|
708
|
+
status: response.status,
|
|
709
|
+
statusText: response.statusText,
|
|
710
|
+
headers: newHeaders
|
|
711
|
+
});
|
|
712
|
+
};
|
|
713
|
+
}
|
|
561
714
|
export {
|
|
562
|
-
createApp
|
|
715
|
+
createApp,
|
|
716
|
+
cors,
|
|
717
|
+
BodyParseError
|
|
563
718
|
};
|
package/dist/router.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface CompiledPath {
|
|
|
12
12
|
paramNames: string[];
|
|
13
13
|
/** Names of optional parameters */
|
|
14
14
|
optionalParams: string[];
|
|
15
|
+
/** Whether this path ends with a wildcard catch-all */
|
|
16
|
+
isWildcard: boolean;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Compile a path pattern into a regex and extract parameter names.
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mCAAmC;IACnC,cAAc,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mCAAmC;IACnC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,uDAAuD;IACvD,UAAU,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA8DtD;AAgBD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAa5F;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC1C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAUT"}
|
package/dist/routes/find.d.ts
CHANGED
|
@@ -47,6 +47,13 @@ export declare function findRoute(routes: Route[], method: string, path: string)
|
|
|
47
47
|
* Check if any route matches the path (regardless of method).
|
|
48
48
|
*/
|
|
49
49
|
export declare function hasMatchingPath(routes: Route[], path: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Find the first route whose path matches, regardless of HTTP method.
|
|
52
|
+
*
|
|
53
|
+
* Used by the OPTIONS/CORS preflight handler to locate group middleware
|
|
54
|
+
* attached to a route at this path.
|
|
55
|
+
*/
|
|
56
|
+
export declare function findRouteByPath(routes: Route[], path: string): RouteMatch | null;
|
|
50
57
|
/**
|
|
51
58
|
* Get all allowed HTTP methods for a given path.
|
|
52
59
|
* Respects route constraints when determining matches.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../src/routes/find.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC/B,kEAAkE;IAClE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,oGAAoG;IACpG,cAAc,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAiC3F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAc1F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMtE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYzE"}
|
|
1
|
+
{"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../src/routes/find.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC/B,kEAAkE;IAClE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,oGAAoG;IACpG,cAAc,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAiC3F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAc1F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMtE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAQhF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/routes/group.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,MAAM,mBAAmB,CAAC;AAG3B,MAAM,MAAM,UAAU,GAAG,CACxB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,EACnD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,eAAe,CAAC,EAAE,UAAU,EAAE,KAC1B,YAAY,CAAC;AAElB;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,UAAU,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,UAAU,GAClB,WAAW,
|
|
1
|
+
{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/routes/group.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,MAAM,mBAAmB,CAAC;AAG3B,MAAM,MAAM,UAAU,GAAG,CACxB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,EACnD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,eAAe,CAAC,EAAE,UAAU,EAAE,KAC1B,YAAY,CAAC;AAElB;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,UAAU,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,UAAU,GAClB,WAAW,CAuDb"}
|
package/dist/routes/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { compilePattern, createRouteBuilder, wrapBuilderWithNamePrefix } from "./builder.js";
|
|
2
|
-
export { findRoute, getAllowedMethods, hasMatchingPath, type RouteMatch, type RouteResolution, resolveRoute, } from "./find.js";
|
|
2
|
+
export { findRoute, findRouteByPath, getAllowedMethods, hasMatchingPath, type RouteMatch, type RouteResolution, resolveRoute, } from "./find.js";
|
|
3
3
|
export { type AddRouteFn, createGroupRouter } from "./group.js";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EACN,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EACN,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -2,8 +2,10 @@ import type { HandlerResponse } from "./handlerResponse.js";
|
|
|
2
2
|
import type { RequestContext } from "./requestContext.js";
|
|
3
3
|
/**
|
|
4
4
|
* Configuration options for creating a Bunary app.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam TLocals — Shape of `ctx.locals` (must match `createApp<TLocals>()`)
|
|
5
7
|
*/
|
|
6
|
-
export interface AppOptions {
|
|
8
|
+
export interface AppOptions<TLocals extends object = Record<string, unknown>> {
|
|
7
9
|
/** Base path prefix for all routes (default: "") */
|
|
8
10
|
basePath?: string;
|
|
9
11
|
/**
|
|
@@ -23,7 +25,7 @@ export interface AppOptions {
|
|
|
23
25
|
* });
|
|
24
26
|
* ```
|
|
25
27
|
*/
|
|
26
|
-
onNotFound?: (ctx: RequestContext) => Response | HandlerResponse | Promise<Response | HandlerResponse>;
|
|
28
|
+
onNotFound?: (ctx: RequestContext<TLocals>) => Response | HandlerResponse | Promise<Response | HandlerResponse>;
|
|
27
29
|
/**
|
|
28
30
|
* Custom handler for 405 Method Not Allowed responses.
|
|
29
31
|
* Called when a route matches the path but not the HTTP method.
|
|
@@ -45,7 +47,7 @@ export interface AppOptions {
|
|
|
45
47
|
* });
|
|
46
48
|
* ```
|
|
47
49
|
*/
|
|
48
|
-
onMethodNotAllowed?: (ctx: RequestContext
|
|
50
|
+
onMethodNotAllowed?: (ctx: RequestContext<TLocals>, allowedMethods: string[]) => Response | HandlerResponse | Promise<Response | HandlerResponse>;
|
|
49
51
|
/**
|
|
50
52
|
* Custom handler for 500 Internal Server Error responses.
|
|
51
53
|
* Called when a route handler or middleware throws an error.
|
|
@@ -67,6 +69,6 @@ export interface AppOptions {
|
|
|
67
69
|
* });
|
|
68
70
|
* ```
|
|
69
71
|
*/
|
|
70
|
-
onError?: (ctx: RequestContext
|
|
72
|
+
onError?: (ctx: RequestContext<TLocals>, error: unknown) => Response | HandlerResponse | Promise<Response | HandlerResponse>;
|
|
71
73
|
}
|
|
72
74
|
//# sourceMappingURL=appOptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appOptions.d.ts","sourceRoot":"","sources":["../../src/types/appOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"appOptions.d.ts","sourceRoot":"","sources":["../../src/types/appOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,UAAU,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3E,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,CACZ,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,KACxB,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC,CAAC;IACtE;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,kBAAkB,CAAC,EAAE,CACpB,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,EAC5B,cAAc,EAAE,MAAM,EAAE,KACpB,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC,CAAC;IACtE;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,CACT,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,EAC5B,KAAK,EAAE,OAAO,KACV,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC,CAAC;CACtE"}
|
|
@@ -3,65 +3,74 @@ import type { GroupOptions } from "./groupOptions.js";
|
|
|
3
3
|
import type { GroupCallback } from "./groupRouter.js";
|
|
4
4
|
import type { ListenOptions } from "./listenOptions.js";
|
|
5
5
|
import type { Middleware } from "./middleware.js";
|
|
6
|
+
import type { PathParams } from "./pathParams.js";
|
|
6
7
|
import type { RouteBuilder } from "./routeBuilder.js";
|
|
7
8
|
import type { RouteHandler } from "./routeHandler.js";
|
|
8
9
|
import type { RouteInfo } from "./routeInfo.js";
|
|
9
10
|
/**
|
|
10
11
|
* The Bunary application instance for HTTP routing and middleware.
|
|
11
12
|
*
|
|
13
|
+
* @typeParam TLocals — Shape of the per-request `locals` store. Set via
|
|
14
|
+
* `createApp<TLocals>()` and propagated to all handlers and middleware.
|
|
15
|
+
*
|
|
12
16
|
* @example
|
|
13
17
|
* ```ts
|
|
14
|
-
*
|
|
18
|
+
* interface Locals { user: User }
|
|
19
|
+
*
|
|
20
|
+
* const app = createApp<Locals>();
|
|
15
21
|
*
|
|
16
22
|
* app.get("/", () => ({ message: "Hello!" }));
|
|
17
|
-
* app.get("/users/:id", (ctx) => ({
|
|
23
|
+
* app.get<{ id: string }>("/users/:id", (ctx) => ({
|
|
24
|
+
* id: ctx.params.id, // string
|
|
25
|
+
* user: ctx.locals.user, // User
|
|
26
|
+
* }));
|
|
18
27
|
*
|
|
19
28
|
* app.listen(3000);
|
|
20
29
|
* ```
|
|
21
30
|
*/
|
|
22
|
-
export interface BunaryApp {
|
|
31
|
+
export interface BunaryApp<TLocals extends object = Record<string, unknown>> {
|
|
23
32
|
/**
|
|
24
33
|
* Register a GET route.
|
|
25
34
|
* @param path - URL path pattern (supports :param and :param? syntax)
|
|
26
35
|
* @param handler - Function to handle requests
|
|
27
36
|
*/
|
|
28
|
-
get: (path: string, handler: RouteHandler) => RouteBuilder
|
|
37
|
+
get: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
29
38
|
/**
|
|
30
39
|
* Register a POST route.
|
|
31
40
|
* @param path - URL path pattern (supports :param and :param? syntax)
|
|
32
41
|
* @param handler - Function to handle requests
|
|
33
42
|
*/
|
|
34
|
-
post: (path: string, handler: RouteHandler) => RouteBuilder
|
|
43
|
+
post: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
35
44
|
/**
|
|
36
45
|
* Register a PUT route.
|
|
37
46
|
* @param path - URL path pattern (supports :param and :param? syntax)
|
|
38
47
|
* @param handler - Function to handle requests
|
|
39
48
|
*/
|
|
40
|
-
put: (path: string, handler: RouteHandler) => RouteBuilder
|
|
49
|
+
put: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
41
50
|
/**
|
|
42
51
|
* Register a DELETE route.
|
|
43
52
|
* @param path - URL path pattern (supports :param and :param? syntax)
|
|
44
53
|
* @param handler - Function to handle requests
|
|
45
54
|
*/
|
|
46
|
-
delete: (path: string, handler: RouteHandler) => RouteBuilder
|
|
55
|
+
delete: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
47
56
|
/**
|
|
48
57
|
* Register a PATCH route.
|
|
49
58
|
* @param path - URL path pattern (supports :param and :param? syntax)
|
|
50
59
|
* @param handler - Function to handle requests
|
|
51
60
|
*/
|
|
52
|
-
patch: (path: string, handler: RouteHandler) => RouteBuilder
|
|
61
|
+
patch: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
53
62
|
/**
|
|
54
63
|
* Add middleware to the request pipeline.
|
|
55
64
|
* Middleware executes in registration order.
|
|
56
65
|
* @param middleware - Middleware function
|
|
57
66
|
*/
|
|
58
|
-
use: (middleware: Middleware) => BunaryApp
|
|
67
|
+
use: (middleware: Middleware<TLocals>) => BunaryApp<TLocals>;
|
|
59
68
|
/**
|
|
60
69
|
* Create a route group with shared prefix, middleware, or name prefix.
|
|
61
70
|
* @param prefix - URL prefix for all routes in the group
|
|
62
71
|
* @param callback - Function to define routes within the group
|
|
63
72
|
*/
|
|
64
|
-
group: ((prefix: string, callback: GroupCallback) => BunaryApp) & ((options: GroupOptions
|
|
73
|
+
group: ((prefix: string, callback: GroupCallback<TLocals>) => BunaryApp<TLocals>) & ((options: GroupOptions<TLocals>, callback: GroupCallback<TLocals>) => BunaryApp<TLocals>);
|
|
65
74
|
/**
|
|
66
75
|
* Generate a URL for a named route.
|
|
67
76
|
* @param name - The route name
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bunaryApp.d.ts","sourceRoot":"","sources":["../../src/types/bunaryApp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"bunaryApp.d.ts","sourceRoot":"","sources":["../../src/types/bunaryApp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,SAAS,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1E;;;;OAIG;IACH,GAAG,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAE3B;;;;OAIG;IACH,IAAI,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAE3B;;;;OAIG;IACH,GAAG,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAE3B;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAE3B;;;;OAIG;IACH,KAAK,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAE3B;;;;OAIG;IACH,GAAG,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC;IAE7D;;;;OAIG;IACH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC,GAChF,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAE5F;;;;;;OAMG;IACH,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAC;IAE1E;;;;OAIG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAEpC;;;OAGG;IACH,SAAS,EAAE,MAAM,SAAS,EAAE,CAAC;IAE7B;;;;;;;;;;OAUG;IACH,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC,GAC3D,CAAC,CAAC,OAAO,EAAE,aAAa,KAAK,YAAY,CAAC,CAAC;IAE5C;;;;OAIG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/C"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Middleware } from "./middleware.js";
|
|
2
2
|
/**
|
|
3
3
|
* Options for route groups.
|
|
4
|
+
*
|
|
5
|
+
* @typeParam TLocals — Shape of `ctx.locals` (inherited from `createApp<TLocals>()`)
|
|
4
6
|
*/
|
|
5
|
-
export interface GroupOptions {
|
|
7
|
+
export interface GroupOptions<TLocals extends object = Record<string, unknown>> {
|
|
6
8
|
/** URL prefix for all routes in the group */
|
|
7
9
|
prefix: string;
|
|
8
10
|
/** Middleware to apply to all routes in the group */
|
|
9
|
-
middleware?: Middleware[];
|
|
11
|
+
middleware?: Middleware<TLocals>[];
|
|
10
12
|
/** Name prefix for all routes in the group */
|
|
11
13
|
name?: string;
|
|
12
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groupOptions.d.ts","sourceRoot":"","sources":["../../src/types/groupOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD
|
|
1
|
+
{"version":3,"file":"groupOptions.d.ts","sourceRoot":"","sources":["../../src/types/groupOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7E,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
import type { GroupOptions } from "./groupOptions.js";
|
|
2
|
+
import type { PathParams } from "./pathParams.js";
|
|
2
3
|
import type { RouteBuilder } from "./routeBuilder.js";
|
|
3
4
|
import type { RouteHandler } from "./routeHandler.js";
|
|
4
5
|
/**
|
|
5
6
|
* Router interface for route groups.
|
|
6
7
|
* Provides the same routing methods as BunaryApp but scoped to a group.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam TLocals — Shape of `ctx.locals` (inherited from `createApp<TLocals>()`)
|
|
7
10
|
*/
|
|
8
|
-
export interface GroupRouter {
|
|
11
|
+
export interface GroupRouter<TLocals extends object = Record<string, unknown>> {
|
|
9
12
|
/** Register a GET route */
|
|
10
|
-
get: (path: string, handler: RouteHandler) => RouteBuilder
|
|
13
|
+
get: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
11
14
|
/** Register a POST route */
|
|
12
|
-
post: (path: string, handler: RouteHandler) => RouteBuilder
|
|
15
|
+
post: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
13
16
|
/** Register a PUT route */
|
|
14
|
-
put: (path: string, handler: RouteHandler) => RouteBuilder
|
|
17
|
+
put: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
15
18
|
/** Register a DELETE route */
|
|
16
|
-
delete: (path: string, handler: RouteHandler) => RouteBuilder
|
|
19
|
+
delete: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
17
20
|
/** Register a PATCH route */
|
|
18
|
-
patch: (path: string, handler: RouteHandler) => RouteBuilder
|
|
21
|
+
patch: <P extends PathParams = PathParams>(path: string, handler: RouteHandler<TLocals, P>) => RouteBuilder<TLocals>;
|
|
19
22
|
/** Create a nested route group */
|
|
20
|
-
group: ((prefix: string, callback: GroupCallback) => GroupRouter) & ((options: GroupOptions
|
|
23
|
+
group: ((prefix: string, callback: GroupCallback<TLocals>) => GroupRouter<TLocals>) & ((options: GroupOptions<TLocals>, callback: GroupCallback<TLocals>) => GroupRouter<TLocals>);
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
23
26
|
* Callback function for defining routes within a group.
|
|
27
|
+
*
|
|
28
|
+
* @typeParam TLocals — Shape of `ctx.locals` (inherited from `createApp<TLocals>()`)
|
|
24
29
|
*/
|
|
25
|
-
export type GroupCallback = (router: GroupRouter) => void;
|
|
30
|
+
export type GroupCallback<TLocals extends object = Record<string, unknown>> = (router: GroupRouter<TLocals>) => void;
|
|
26
31
|
//# sourceMappingURL=groupRouter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groupRouter.d.ts","sourceRoot":"","sources":["../../src/types/groupRouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"groupRouter.d.ts","sourceRoot":"","sources":["../../src/types/groupRouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5E,2BAA2B;IAC3B,GAAG,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3B,4BAA4B;IAC5B,IAAI,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3B,2BAA2B;IAC3B,GAAG,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3B,8BAA8B;IAC9B,MAAM,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3B,6BAA6B;IAC7B,KAAK,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3B,kCAAkC;IAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,CAAC,GAClF,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;CAC9F;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAC7E,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KACxB,IAAI,CAAC"}
|
|
@@ -3,19 +3,24 @@ import type { RequestContext } from "./requestContext.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Middleware function for processing requests in a pipeline.
|
|
5
5
|
*
|
|
6
|
+
* Middleware receives the app-level `TLocals` type but not per-route
|
|
7
|
+
* `TParams`, since middleware runs before route matching resolves params.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam TLocals — Shape of `ctx.locals` (inherited from `createApp<TLocals>()`)
|
|
10
|
+
*
|
|
6
11
|
* @param ctx - The request context
|
|
7
12
|
* @param next - Function to call the next middleware or route handler
|
|
8
13
|
* @returns Response data or void (if next() handles it)
|
|
9
14
|
*
|
|
10
15
|
* @example
|
|
11
16
|
* ```ts
|
|
12
|
-
* const logger: Middleware = async (ctx, next) => {
|
|
13
|
-
*
|
|
17
|
+
* const logger: Middleware<{ requestId: string }> = async (ctx, next) => {
|
|
18
|
+
* ctx.locals.requestId = crypto.randomUUID();
|
|
14
19
|
* const response = await next();
|
|
15
|
-
* console.log(
|
|
20
|
+
* console.log(`[${ctx.locals.requestId}] done`);
|
|
16
21
|
* return response;
|
|
17
22
|
* };
|
|
18
23
|
* ```
|
|
19
24
|
*/
|
|
20
|
-
export type Middleware = (ctx: RequestContext
|
|
25
|
+
export type Middleware<TLocals extends object = Record<string, unknown>> = (ctx: RequestContext<TLocals>, next: () => Promise<HandlerResponse>) => HandlerResponse | Promise<HandlerResponse>;
|
|
21
26
|
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/types/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/types/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAC1E,GAAG,EAAE,cAAc,CAAC,OAAO,CAAC,EAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,KAChC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC"}
|
|
@@ -2,20 +2,31 @@ import type { PathParams } from "./pathParams.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Context object passed to route handlers containing request data.
|
|
4
4
|
*
|
|
5
|
+
* @typeParam TLocals — Shape of the per-request `locals` store. Defaults to
|
|
6
|
+
* `Record<string, unknown>` for backward compatibility. Narrow it via
|
|
7
|
+
* `createApp<TLocals>()` to get type-safe middleware→handler data passing.
|
|
8
|
+
* @typeParam TParams — Shape of the route parameters. Defaults to `PathParams`
|
|
9
|
+
* (`Record<string, string | undefined>`). Narrow it per-route via
|
|
10
|
+
* `app.get<TParams>()` to get typed parameter access.
|
|
11
|
+
*
|
|
5
12
|
* @example
|
|
6
13
|
* ```ts
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
14
|
+
* interface Locals { user: User; requestId: string }
|
|
15
|
+
*
|
|
16
|
+
* const app = createApp<Locals>();
|
|
17
|
+
*
|
|
18
|
+
* app.get<{ id: string }>("/users/:id", (ctx) => {
|
|
19
|
+
* ctx.params.id; // string
|
|
20
|
+
* ctx.locals.user; // User
|
|
21
|
+
* ctx.locals.requestId; // string
|
|
11
22
|
* });
|
|
12
23
|
* ```
|
|
13
24
|
*/
|
|
14
|
-
export interface RequestContext {
|
|
25
|
+
export interface RequestContext<TLocals extends object = Record<string, unknown>, TParams extends PathParams = PathParams> {
|
|
15
26
|
/** The original Bun Request object */
|
|
16
27
|
request: Request;
|
|
17
28
|
/** Path parameters extracted from the route pattern */
|
|
18
|
-
params:
|
|
29
|
+
params: TParams;
|
|
19
30
|
/** Query parameters from the URL search string */
|
|
20
31
|
query: URLSearchParams;
|
|
21
32
|
/**
|
|
@@ -31,6 +42,60 @@ export interface RequestContext {
|
|
|
31
42
|
* });
|
|
32
43
|
* ```
|
|
33
44
|
*/
|
|
34
|
-
locals:
|
|
45
|
+
locals: TLocals;
|
|
46
|
+
/**
|
|
47
|
+
* Parse the request body as JSON.
|
|
48
|
+
*
|
|
49
|
+
* Thin wrapper around `request.json()` with error handling.
|
|
50
|
+
* Throws `BodyParseError` if the body is not valid JSON.
|
|
51
|
+
*
|
|
52
|
+
* @typeParam T — Expected shape of the parsed JSON body
|
|
53
|
+
* @returns The parsed JSON body
|
|
54
|
+
* @throws {BodyParseError} If the body cannot be parsed as JSON
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* app.post("/users", async (ctx) => {
|
|
59
|
+
* const body = await ctx.json<{ name: string }>();
|
|
60
|
+
* return { id: 1, name: body.name };
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
json: <T = unknown>() => Promise<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Get the request body as a string.
|
|
67
|
+
*
|
|
68
|
+
* Thin wrapper around `request.text()`.
|
|
69
|
+
*
|
|
70
|
+
* @returns The request body as text
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* app.post("/echo", async (ctx) => {
|
|
75
|
+
* const text = await ctx.text();
|
|
76
|
+
* return { echo: text };
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
text: () => Promise<string>;
|
|
81
|
+
/**
|
|
82
|
+
* Parse the request body as FormData.
|
|
83
|
+
*
|
|
84
|
+
* Thin wrapper around `request.formData()` with error handling.
|
|
85
|
+
* Throws `BodyParseError` if the body cannot be parsed as form data.
|
|
86
|
+
*
|
|
87
|
+
* @returns The parsed FormData
|
|
88
|
+
* @throws {BodyParseError} If the body cannot be parsed as form data
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* app.post("/upload", async (ctx) => {
|
|
93
|
+
* const form = await ctx.formData();
|
|
94
|
+
* const name = form.get("name");
|
|
95
|
+
* return { name };
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
formData: () => ReturnType<Request["formData"]>;
|
|
35
100
|
}
|
|
36
101
|
//# sourceMappingURL=requestContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestContext.d.ts","sourceRoot":"","sources":["../../src/types/requestContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD
|
|
1
|
+
{"version":3,"file":"requestContext.d.ts","sourceRoot":"","sources":["../../src/types/requestContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,cAAc,CAC9B,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChD,OAAO,SAAS,UAAU,GAAG,UAAU;IAEvC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,eAAe,CAAC;IACvB;;;;;;;;;;;;OAYG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAI,EAAE,CAAC,CAAC,GAAG,OAAO,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAEpC;;;;;;;;;;;;;;OAcG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,EAAE,MAAM,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;CAChD"}
|
package/dist/types/route.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/types/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,KAAK;IACrB,iCAAiC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,sCAAsC;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,gCAAgC;IAChC,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/types/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,KAAK;IACrB,iCAAiC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,sCAAsC;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,gCAAgC;IAChC,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB"}
|
|
@@ -2,23 +2,25 @@ import type { BunaryApp } from "./bunaryApp.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Fluent builder for route configuration.
|
|
4
4
|
* Allows chaining methods like name(), where(), etc.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam TLocals — Shape of `ctx.locals` (inherited from `createApp<TLocals>()`)
|
|
5
7
|
*/
|
|
6
|
-
export interface RouteBuilder extends BunaryApp {
|
|
8
|
+
export interface RouteBuilder<TLocals extends object = Record<string, unknown>> extends BunaryApp<TLocals> {
|
|
7
9
|
/** Assign a name to the route for URL generation */
|
|
8
|
-
name: (name: string) => RouteBuilder
|
|
10
|
+
name: (name: string) => RouteBuilder<TLocals>;
|
|
9
11
|
/** Add a regex constraint to a route parameter */
|
|
10
|
-
where: ((param: string, pattern: RegExp | string) => RouteBuilder) & ((constraints: Record<string, RegExp | string>) => RouteBuilder);
|
|
12
|
+
where: ((param: string, pattern: RegExp | string) => RouteBuilder<TLocals>) & ((constraints: Record<string, RegExp | string>) => RouteBuilder<TLocals>);
|
|
11
13
|
/** Constrain parameter to digits only */
|
|
12
|
-
whereNumber: (param: string) => RouteBuilder
|
|
14
|
+
whereNumber: (param: string) => RouteBuilder<TLocals>;
|
|
13
15
|
/** Constrain parameter to letters only */
|
|
14
|
-
whereAlpha: (param: string) => RouteBuilder
|
|
16
|
+
whereAlpha: (param: string) => RouteBuilder<TLocals>;
|
|
15
17
|
/** Constrain parameter to letters and digits only */
|
|
16
|
-
whereAlphaNumeric: (param: string) => RouteBuilder
|
|
18
|
+
whereAlphaNumeric: (param: string) => RouteBuilder<TLocals>;
|
|
17
19
|
/** Constrain parameter to UUID format */
|
|
18
|
-
whereUuid: (param: string) => RouteBuilder
|
|
20
|
+
whereUuid: (param: string) => RouteBuilder<TLocals>;
|
|
19
21
|
/** Constrain parameter to ULID format */
|
|
20
|
-
whereUlid: (param: string) => RouteBuilder
|
|
22
|
+
whereUlid: (param: string) => RouteBuilder<TLocals>;
|
|
21
23
|
/** Constrain parameter to specific allowed values */
|
|
22
|
-
whereIn: (param: string, values: string[]) => RouteBuilder
|
|
24
|
+
whereIn: (param: string, values: string[]) => RouteBuilder<TLocals>;
|
|
23
25
|
}
|
|
24
26
|
//# sourceMappingURL=routeBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeBuilder.d.ts","sourceRoot":"","sources":["../../src/types/routeBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"routeBuilder.d.ts","sourceRoot":"","sources":["../../src/types/routeBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAC7E,SAAQ,SAAS,CAAC,OAAO,CAAC;IAC1B,oDAAoD;IACpD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9C,kDAAkD;IAClD,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC,GAC1E,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,yCAAyC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IACtD,0CAA0C;IAC1C,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IACrD,qDAAqD;IACrD,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IAC5D,yCAAyC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IACpD,yCAAyC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IACpD,qDAAqD;IACrD,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;CACpE"}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import type { HandlerResponse } from "./handlerResponse.js";
|
|
2
|
+
import type { PathParams } from "./pathParams.js";
|
|
2
3
|
import type { RequestContext } from "./requestContext.js";
|
|
3
4
|
/**
|
|
4
5
|
* Route handler function that processes incoming requests.
|
|
5
6
|
*
|
|
7
|
+
* @typeParam TLocals — Shape of `ctx.locals` (inherited from `createApp<TLocals>()`)
|
|
8
|
+
* @typeParam TParams — Shape of `ctx.params` (specified per-route via `app.get<TParams>()`)
|
|
9
|
+
*
|
|
6
10
|
* @param ctx - The request context containing request, params, and query
|
|
7
11
|
* @returns Response data (object for JSON, Response for custom, or primitive)
|
|
8
12
|
*
|
|
9
13
|
* @example
|
|
10
14
|
* ```ts
|
|
11
|
-
* const handler: RouteHandler = (ctx) => {
|
|
12
|
-
* return {
|
|
15
|
+
* const handler: RouteHandler<{ user: User }, { id: string }> = (ctx) => {
|
|
16
|
+
* return { id: ctx.params.id, name: ctx.locals.user.name };
|
|
13
17
|
* };
|
|
14
18
|
* ```
|
|
15
19
|
*/
|
|
16
|
-
export type RouteHandler = (ctx: RequestContext) => HandlerResponse | Promise<HandlerResponse>;
|
|
20
|
+
export type RouteHandler<TLocals extends object = Record<string, unknown>, TParams extends PathParams = PathParams> = (ctx: RequestContext<TLocals, TParams>) => HandlerResponse | Promise<HandlerResponse>;
|
|
17
21
|
//# sourceMappingURL=routeHandler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeHandler.d.ts","sourceRoot":"","sources":["../../src/types/routeHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"routeHandler.d.ts","sourceRoot":"","sources":["../../src/types/routeHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,YAAY,CACvB,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChD,OAAO,SAAS,UAAU,GAAG,UAAU,IACpC,CAAC,GAAG,EAAE,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC"}
|