@bepalo/router 1.2.13 → 1.5.20

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/README.md CHANGED
@@ -49,16 +49,16 @@
49
49
  ## ✨ Features
50
50
 
51
51
  - ⚡ **High Performance** - Built on a radix tree for O(k) route matching (where k is path length)
52
- - 🎯 **Flexible Routing** - Support for path parameters, wildcards (`*`, `.*`, `**`, `.**`), and all HTTP methods
53
- - 🎭 **Multiple Handler Types** - Filters, hooks, handlers, fallbacks, and catchers
52
+ - 🎯 **Flexible Routing Engine** - Support for path parameters, wildcards (`*`, `.*`, `**`, `.**`), and all HTTP methods
53
+ - 🎭 **Multiple Handler Types** - Filters, hooks, afters, handlers, fallbacks, and catchers
54
54
  - 🔌 **Middleware Pipeline** - Chain multiple handlers with early exit capability
55
55
  - 🛡️ **Error Handling** - Built-in error catching with contextual error handlers
56
56
  - 🔄 **Method-Based Routing** - Separate routing trees for each HTTP method
57
- - 📦 **Local Dependencies** - Only @bepalo dependencies
57
+ - 📦 **Local Dependencies** - Minimal Dependencies — Only internal @bepalo packages
58
58
  - 🌐 **Runtime Agnostic** - Works with Bun, Deno, Node.js, and other runtimes
59
59
  - 🔧 **TypeScript Ready** - Full type definitions included
60
- - 🧩 **Router Composition** - Append one router to another with a path prefix.
61
- - 🛠️ **Helper Functions** - Built-in response helpers (json, html, parseBody, upload, etc.)
60
+ - 🧩 **Composable Router Architecture** - Append one router to another with a path prefix.
61
+ - 🛠️ **Built-in Helper Utilities** - Built-in response helpers (json, html, parseBody, upload, etc.)
62
62
  - 🔐 **Middleware Integration** - CORS, rate limiting, authentication helpers
63
63
 
64
64
  ## 🚀 Get Started
@@ -226,7 +226,7 @@ router.filter(
226
226
 
227
227
  // Main route
228
228
  router.handle("GET /", () =>
229
- html("<h1>Welcome! Enjoy using @beplao/router</h1>"),
229
+ html("<h1>Welcome! Enjoy using @bepalo/router</h1>"),
230
230
  );
231
231
  router.handle("GET /status", () => status(200));
232
232
 
@@ -351,7 +351,7 @@ Deno.serve(
351
351
  #### Nodejs
352
352
 
353
353
  ```js
354
- // Nodejs example. very slow
354
+ // Node.js compatibility example (uses Fetch bridge; not optimized)
355
355
  http
356
356
  .createServer(async (req, res) => {
357
357
  const url = new URL(req.url || "/", `http://${req.headers.host}`);
@@ -541,6 +541,7 @@ router.respond(
541
541
 
542
542
  ```ts
543
543
  import {
544
+ Status, // Status enum
544
545
  status, // HTTP status response
545
546
  redirect, // Redirect response with location header set
546
547
  forward, // forward to other path within the router.
@@ -568,10 +569,45 @@ const router = new Router();
568
569
  router.handle("GET /text", () => text("Hello World"));
569
570
  router.handle("GET /html", () => html("<h1>Title</h1>"));
570
571
  router.handle("GET /json", () => json({ data: "value" }));
571
- router.handle("GET /status", () => status(204, null)); // No Content
572
+ router.handle("GET /status", () => status(Status._204_NoContent, null)); // No Content
572
573
  router.handle("GET /intro.mp4", () => blob(Bun.file("./intro.mp4")));
573
574
  router.handle("GET /download", () => octetStream(Bun.file("./intro.mp4")));
574
575
 
576
+ router.handle("GET /new-location", () => html("GET new-location"));
577
+ // router.handle("POST /new-location", () => html("POST new-location"));
578
+ router.handle<CTXBody>("POST /new-location", [
579
+ parseBody({ once: true, clone: true }),
580
+ (req, { body }) => console.log(body),
581
+ forward("/new-location2"),
582
+ ]);
583
+ router.handle<CTXBody>("POST /new-location2", [
584
+ parseBody({ once: true, clone: false }),
585
+ (req, { body }) => console.log(body),
586
+ () => html("POST new-location2"),
587
+ ]);
588
+ router.handle("GET /redirected", () => redirect("/new-location"));
589
+ router.handle("GET /forwarded", forward("/new-location"));
590
+ // this would set the headers:
591
+ // "x-forwarded-path": "/forwarded"
592
+ // "x-original-path": "/forwarded"
593
+ router.handle<CTXBody>("PUT /forwarded-with-new-method", [
594
+ parseBody({ once: true, clone: true }),
595
+ (req, { body }) => console.log(body),
596
+ forward("/new-location", { method: "POST" }),
597
+ ]);
598
+ // this would set the headers:
599
+ // "x-forwarded-method": "PUT"
600
+ // "x-forwarded-path": "/new-location"
601
+ // "x-original-path": "/forwarded-with-new-method"
602
+ router.handle("GET /forwarded-conditional", function (this: Router, req, ctx) {
603
+ if (req.headers.get("authorization"))
604
+ return forward("/new-location").bind(this)(req, ctx);
605
+ // or return forward("/new-location").apply(this, [req, ctx]);
606
+ // NOTE: be careful when binding instance `router` instead of `this`
607
+ // as it might be called from a different router due to append.
608
+ return status(Status._401_Unauthorized);
609
+ });
610
+
575
611
  router.handle<CTXCookie>("GET /cookie", [
576
612
  parseCookie(),
577
613
  (req, { cookie }) => json({ cookie }),
@@ -580,7 +616,8 @@ router.handle<CTXCookie>("GET /cookie", [
580
616
  router.handle<CTXBody>("POST /cookie", [
581
617
  parseBody(),
582
618
  (req, { body }) => {
583
- return status(200, "OK", {
619
+ return status(Status._200_OK, "OK", {
620
+ // or `, undefined, {` and the status text will be set
584
621
  headers: [
585
622
  ...Object.entries(body).map(([name, value]) =>
586
623
  setCookie(name, String(value), {
@@ -595,24 +632,55 @@ router.handle<CTXBody>("POST /cookie", [
595
632
 
596
633
  router.handle("DELETE /cookie/:name", [
597
634
  (req, ctx) =>
598
- status(200, "OK", {
635
+ status(Status._200_OK, undefined, {
599
636
  headers: [clearCookie(ctx.params.name, { path: "/" })],
600
637
  }),
601
638
  ]);
602
639
 
640
+ // be sure to create ./upload folder for this example
603
641
  router.handle<CTXUpload>("POST /upload", [
604
642
  (req, ctx) => {
605
643
  let file: Bun.BunFile;
606
644
  let fileWriter: Bun.FileSink;
607
645
  return parseUploadStreaming({
608
646
  allowedTypes: ["image/jpeg"],
609
- async onFileStart(uploadId, fieldName, fileName, contentType, fileSize) {
610
- console.log(fileSize);
647
+ maxFileSize: 5 * 1024 * 1024,
648
+ maxTotalSize: 5 * 1024 * 1024 + 1024,
649
+ maxFields: 1,
650
+ maxFiles: 1,
651
+ // uploadIdGenerator: () =>
652
+ // `upload_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
653
+ async onUploadStart(uploadId, totalSize) {
654
+ console.log("onUploadStart", { uploadId, totalSize });
655
+ },
656
+ async onError(uploadId, error) {
657
+ console.error("onError", uploadId, error);
658
+ },
659
+ async onFileError(uploadId, fieldName, fileName, error) {
660
+ console.error("onFileError", uploadId, error);
661
+ },
662
+ async onField(uploadId, fieldName, value) {
663
+ console.log("onField", { uploadId, fieldName, value });
664
+ },
665
+ async onFileStart(uploadId, fieldName, fileName, contentType) {
666
+ console.log("onFileStart", {
667
+ uploadId,
668
+ fieldName,
669
+ fileName,
670
+ contentType,
671
+ });
611
672
  const ext = fileName.substring(fileName.lastIndexOf("."));
612
- file = Bun.file("./uploads/" + uploadId + ext);
673
+ const customFilename = uploadId + ext;
674
+ file = Bun.file("./uploads/" + customFilename);
613
675
  fileWriter = file.writer();
676
+ return {
677
+ customFilename,
678
+ // metadata
679
+ };
614
680
  },
615
681
  async onFileChunk(uploadId, fieldName, fileName, chunk, offset, isLast) {
682
+ const chunkSize = chunk.byteLength;
683
+ console.log("onFileChunk", { uploadId, chunkSize, offset, isLast });
616
684
  fileWriter.write(chunk);
617
685
  },
618
686
  async onFileComplete(
@@ -623,17 +691,26 @@ router.handle<CTXUpload>("POST /upload", [
623
691
  customFilename,
624
692
  metadata,
625
693
  ) {
626
- console.log({ uploadId, fieldName, fileName, fileSize });
694
+ console.log("onFileComplete", {
695
+ uploadId,
696
+ fieldName,
697
+ fileName,
698
+ fileSize,
699
+ customFilename,
700
+ metadata,
701
+ });
702
+ if (fileWriter) {
703
+ fileWriter.end();
704
+ }
627
705
  },
628
706
  async onUploadComplete(uploadId, success) {
629
- console.log({ uploadId, success });
707
+ console.log("onUploadComplete", { uploadId, success });
630
708
  },
631
709
  })(req, ctx);
632
710
  },
633
711
  (req, { uploadId, fields, files }) => {
634
712
  console.log({ uploadId, fields, files });
635
- console.log(files.get("profile"));
636
- return status(200);
713
+ return status(Status._200_OK);
637
714
  },
638
715
  ]);
639
716
  ```
@@ -642,12 +719,21 @@ router.handle<CTXUpload>("POST /upload", [
642
719
 
643
720
  ```ts
644
721
  import {
722
+ type CTXCookie,
723
+ type CTXBody,
724
+ type CTXAuth,
725
+ type CTXUpload,
726
+ parseCookie, // Cookie parser
727
+ parseBody, // Body parser
728
+ parseUploadStreaming, // multi-part-form-data and file upload stream parser
645
729
  cors, // CORS middleware
646
730
  limitRate, // Rate limiting
731
+ authenticate, // Generic authentication middleware
732
+ authorize, // Generic authorization middleware
647
733
  authBasic, // Basic authentication
648
734
  authAPIKey, // API key authentication
649
735
  authJWT, // JWT authentication
650
- } from "@bepalo/router/middlewares";
736
+ } from "@bepalo/router";
651
737
  ```
652
738
 
653
739
  ### 🔧 Advanced Usage
@@ -768,13 +854,14 @@ The router uses a radix tree (trie) data structure for route matching, providing
768
854
  | Feature | @bepalo/router | Express | Hono | Fastify |
769
855
  | ------------------------------- | -------------- | ------- | ---- | ------- |
770
856
  | Radix Tree Routing | ✅ | ❌ | ✅ | ✅ |
771
- | Few Dependencies | ✅ | ❌ | | |
857
+ | Few Dependencies | ✅ | ❌ | ⚠️ | ⚠️ |
772
858
  | TypeScript Native | ✅ | ❌ | ✅ | ✅ |
773
- | Extended Handler Phases | ✅ | ⚠️ | ⚠️ | ⚠️ |
774
- | Built-in Middleware | ✅ | | ✅ | ✅ |
775
- | Runtime Agnostic | ✅ | ❌ | ✅ | |
859
+ | Extended Handler Phases | ✅ | | | ⚠️ |
860
+ | Built-in Middleware | ✅ | ⚠️ | ✅ | ✅ |
861
+ | Runtime Agnostic | ✅ | ❌ | ✅ | ⚠️ |
776
862
  | Router Composition | ✅ | ✅ | ✅ | ✅ |
777
863
  | Structured Multi-Phase Pipeline | ✅ | ❌ | ❌ | ❌ |
864
+ | Server | ❌ | ✅ | ⚠️ | ✅ |
778
865
 
779
866
  ## 📄 License
780
867
 
@@ -1,17 +1,80 @@
1
- import { RouterContext } from "./router";
2
- import { Handler } from "./types";
1
+ import type { BoundHandler, HttpMethod } from "./types";
3
2
  export * from "./upload-stream";
4
- export interface SocketAddress {
5
- address: string;
6
- family: string;
7
- port: number;
3
+ export declare enum Status {
4
+ _100_Continue = 100,
5
+ _101_SwitchingProtocols = 101,
6
+ _102_Processing = 102,
7
+ _103_EarlyHints = 103,
8
+ _200_OK = 200,
9
+ _201_Created = 201,
10
+ _202_Accepted = 202,
11
+ _203_NonAuthoritativeInformation = 203,
12
+ _204_NoContent = 204,
13
+ _205_ResetContent = 205,
14
+ _206_PartialContent = 206,
15
+ _207_MultiStatus = 207,
16
+ _208_AlreadyReported = 208,
17
+ _226_IMUsed = 226,
18
+ _300_MultipleChoices = 300,
19
+ _301_MovedPermanently = 301,
20
+ _302_Found = 302,
21
+ _303_SeeOther = 303,
22
+ _304_NotModified = 304,
23
+ _305_UseProxy = 305,
24
+ _307_TemporaryRedirect = 307,
25
+ _308_PermanentRedirect = 308,
26
+ _400_BadRequest = 400,
27
+ _401_Unauthorized = 401,
28
+ _402_PaymentRequired = 402,
29
+ _403_Forbidden = 403,
30
+ _404_NotFound = 404,
31
+ _405_MethodNotAllowed = 405,
32
+ _406_NotAcceptable = 406,
33
+ _407_ProxyAuthenticationRequired = 407,
34
+ _408_RequestTimeout = 408,
35
+ _409_Conflict = 409,
36
+ _410_Gone = 410,
37
+ _411_LengthRequired = 411,
38
+ _412_PreconditionFailed = 412,
39
+ _413_PayloadTooLarge = 413,
40
+ _414_URITooLong = 414,
41
+ _415_UnsupportedMediaType = 415,
42
+ _416_RangeNotSatisfiable = 416,
43
+ _417_ExpectationFailed = 417,
44
+ _418_IMATeapot = 418,
45
+ _421_MisdirectedRequest = 421,
46
+ _422_UnprocessableEntity = 422,
47
+ _423_Locked = 423,
48
+ _424_FailedDependency = 424,
49
+ _425_TooEarly = 425,
50
+ _426_UpgradeRequired = 426,
51
+ _428_PreconditionRequired = 428,
52
+ _429_TooManyRequests = 429,
53
+ _431_RequestHeaderFieldsTooLarge = 431,
54
+ _451_UnavailableForLegalReasons = 451,
55
+ _500_InternalServerError = 500,
56
+ _501_NotImplemented = 501,
57
+ _502_BadGateway = 502,
58
+ _503_ServiceUnavailable = 503,
59
+ _504_GatewayTimeout = 504,
60
+ _505_HTTPVersionNotSupported = 505,
61
+ _506_VariantAlsoNegotiates = 506,
62
+ _507_InsufficientStorage = 507,
63
+ _508_LoopDetected = 508,
64
+ _510_NotExtended = 510,
65
+ _511_NetworkAuthenticationRequired = 511,
66
+ _419_PageExpired = 419,
67
+ _420_EnhanceYourCalm = 420,
68
+ _450_BlockedbyWindowsParentalControls = 450,
69
+ _498_InvalidToken = 498,
70
+ _499_TokenRequired = 499,
71
+ _509_BandwidthLimitExceeded = 509,
72
+ _526_InvalidSSLCertificate = 526,
73
+ _529_Siteisoverloaded = 529,
74
+ _530_Siteisfrozen = 530,
75
+ _598_NetworkReadTimeoutError = 598,
76
+ _599_NetworkConnectTimeoutError = 599
8
77
  }
9
- export type CTXError = {
10
- error: Error;
11
- };
12
- export type CTXAddress = {
13
- address: SocketAddress;
14
- };
15
78
  export declare function getHttpStatusText(code: number): string;
16
79
  /**
17
80
  * Creates a Response with the specified status code.
@@ -36,14 +99,18 @@ export declare const status: (status: number, content?: string | null, init?: Re
36
99
  */
37
100
  export declare const redirect: (location: string, init?: ResponseInit) => Response;
38
101
  /**
39
- * Forwards the request to another handler internally.
40
- * Does not change the URL or send a redirect to the client.
102
+ * Forwards the request to another route internally.
103
+ * Does not send a redirect to the client but changes the path and method,
104
+ * adds X-Forwarded-[Method|Path] and X-Original-Path headers and calls
105
+ * `(this as Router).respond(newReq, ctx)`.
106
+ * NOTE: parse body only once at the first handler using `parseBody({once: true})`
107
+ * as the body will be consumed at the first parseBody call.
41
108
  * @param {string} path - The new path to forward to
42
109
  * @returns {Response} A Response object with the forwarded request's response
43
110
  */
44
111
  export declare const forward: <XContext = {}>(path: string, options?: {
45
- method: string;
46
- }) => Handler<RouterContext<XContext>>;
112
+ method?: HttpMethod;
113
+ }) => BoundHandler<XContext>;
47
114
  /**
48
115
  * Creates a text/plain Response.
49
116
  * Defaults to status 200 and text/plain content-type if not specified.
@@ -194,53 +261,6 @@ export declare const clearCookie: (name: string, options?: CookieOptions) => Coo
194
261
  * // Returns: { session: "abc123", theme: "dark" }
195
262
  */
196
263
  export declare const parseCookieFromRequest: <Expected extends Record<string, string>>(req: Request) => Expected | undefined;
197
- /**
198
- * Context object containing parsed cookies.
199
- * @typedef {Object} CTXCookie
200
- * @property {Record<string, string>} cookie - Parsed cookies from the request
201
- */
202
- export type CTXCookie = {
203
- cookie: Record<string, string>;
204
- };
205
- /**
206
- * Creates middleware that parses cookies from the request and adds them to the context.
207
- * @returns {Function} A middleware function that adds parsed cookies to context.cookie
208
- * @example
209
- * const cookieParser = parseCookie();
210
- * // Use in respondWith: respondWith({}, cookieParser(), ...otherHandlers)
211
- */
212
- export declare const parseCookie: <Context extends CTXCookie>() => Handler<Context>;
213
- /**
214
- * Context object containing parsed request body.
215
- * @typedef {Object} CTXBody
216
- * @property {Record<string, unknown>} body - Parsed request body data
217
- */
218
- export type CTXBody = {
219
- body: Record<string, unknown>;
220
- };
221
- /**
222
- * Supported media types for request body parsing.
223
- * @typedef {"application/x-www-form-urlencoded"|"application/json"|"text/plain"} SupportedBodyMediaTypes
224
- */
225
- export type SupportedBodyMediaTypes = "application/x-www-form-urlencoded" | "application/json" | "text/plain";
226
- /**
227
- * Creates middleware that parses the request body based on Content-Type.
228
- * Supports url-encoded forms, JSON, and plain text.
229
- * @param {Object} [options] - Configuration options for body parsing
230
- * @param {SupportedBodyMediaTypes|SupportedBodyMediaTypes[]} [options.accept] - Media types to accept (defaults to all supported)
231
- * @param {number} [options.maxSize] - Maximum body size in bytes (defaults to 1MB)
232
- * @returns {Function} A middleware function that adds parsed body to context.body
233
- * @throws {Response} Returns a 415 response if content-type is not accepted
234
- * @throws {Response} Returns a 413 response if body exceeds maxSize
235
- * @throws {Response} Returns a 400 response if body is malformed
236
- * @example
237
- * const bodyParser = parseBody({ maxSize: 5000 });
238
- * // Use in respondWith: respondWith({}, bodyParser(), ...otherHandlers)
239
- */
240
- export declare const parseBody: <Context extends CTXBody>(options?: {
241
- accept?: SupportedBodyMediaTypes | SupportedBodyMediaTypes[];
242
- maxSize?: number;
243
- }) => Handler<Context>;
244
264
  /**
245
265
  * Request handler function type.
246
266
  * @callback RequestHandler
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"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"}
@@ -23,9 +23,85 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
23
23
  });
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.respondWithCatcher = exports.respondWith = exports.parseBody = exports.parseCookie = exports.parseCookieFromRequest = exports.clearCookie = exports.setCookie = exports.send = exports.usp = exports.formData = exports.octetStream = exports.blob = exports.json = exports.html = exports.text = exports.forward = exports.redirect = exports.status = void 0;
26
+ exports.respondWithCatcher = exports.respondWith = exports.parseCookieFromRequest = exports.clearCookie = exports.setCookie = exports.send = exports.usp = exports.formData = exports.octetStream = exports.blob = exports.json = exports.html = exports.text = exports.forward = exports.redirect = exports.status = exports.Status = void 0;
27
27
  exports.getHttpStatusText = getHttpStatusText;
28
28
  __exportStar(require("./upload-stream"), exports);
29
+ var Status;
30
+ (function (Status) {
31
+ Status[Status["_100_Continue"] = 100] = "_100_Continue";
32
+ Status[Status["_101_SwitchingProtocols"] = 101] = "_101_SwitchingProtocols";
33
+ Status[Status["_102_Processing"] = 102] = "_102_Processing";
34
+ Status[Status["_103_EarlyHints"] = 103] = "_103_EarlyHints";
35
+ Status[Status["_200_OK"] = 200] = "_200_OK";
36
+ Status[Status["_201_Created"] = 201] = "_201_Created";
37
+ Status[Status["_202_Accepted"] = 202] = "_202_Accepted";
38
+ Status[Status["_203_NonAuthoritativeInformation"] = 203] = "_203_NonAuthoritativeInformation";
39
+ Status[Status["_204_NoContent"] = 204] = "_204_NoContent";
40
+ Status[Status["_205_ResetContent"] = 205] = "_205_ResetContent";
41
+ Status[Status["_206_PartialContent"] = 206] = "_206_PartialContent";
42
+ Status[Status["_207_MultiStatus"] = 207] = "_207_MultiStatus";
43
+ Status[Status["_208_AlreadyReported"] = 208] = "_208_AlreadyReported";
44
+ Status[Status["_226_IMUsed"] = 226] = "_226_IMUsed";
45
+ Status[Status["_300_MultipleChoices"] = 300] = "_300_MultipleChoices";
46
+ Status[Status["_301_MovedPermanently"] = 301] = "_301_MovedPermanently";
47
+ Status[Status["_302_Found"] = 302] = "_302_Found";
48
+ Status[Status["_303_SeeOther"] = 303] = "_303_SeeOther";
49
+ Status[Status["_304_NotModified"] = 304] = "_304_NotModified";
50
+ Status[Status["_305_UseProxy"] = 305] = "_305_UseProxy";
51
+ Status[Status["_307_TemporaryRedirect"] = 307] = "_307_TemporaryRedirect";
52
+ Status[Status["_308_PermanentRedirect"] = 308] = "_308_PermanentRedirect";
53
+ Status[Status["_400_BadRequest"] = 400] = "_400_BadRequest";
54
+ Status[Status["_401_Unauthorized"] = 401] = "_401_Unauthorized";
55
+ Status[Status["_402_PaymentRequired"] = 402] = "_402_PaymentRequired";
56
+ Status[Status["_403_Forbidden"] = 403] = "_403_Forbidden";
57
+ Status[Status["_404_NotFound"] = 404] = "_404_NotFound";
58
+ Status[Status["_405_MethodNotAllowed"] = 405] = "_405_MethodNotAllowed";
59
+ Status[Status["_406_NotAcceptable"] = 406] = "_406_NotAcceptable";
60
+ Status[Status["_407_ProxyAuthenticationRequired"] = 407] = "_407_ProxyAuthenticationRequired";
61
+ Status[Status["_408_RequestTimeout"] = 408] = "_408_RequestTimeout";
62
+ Status[Status["_409_Conflict"] = 409] = "_409_Conflict";
63
+ Status[Status["_410_Gone"] = 410] = "_410_Gone";
64
+ Status[Status["_411_LengthRequired"] = 411] = "_411_LengthRequired";
65
+ Status[Status["_412_PreconditionFailed"] = 412] = "_412_PreconditionFailed";
66
+ Status[Status["_413_PayloadTooLarge"] = 413] = "_413_PayloadTooLarge";
67
+ Status[Status["_414_URITooLong"] = 414] = "_414_URITooLong";
68
+ Status[Status["_415_UnsupportedMediaType"] = 415] = "_415_UnsupportedMediaType";
69
+ Status[Status["_416_RangeNotSatisfiable"] = 416] = "_416_RangeNotSatisfiable";
70
+ Status[Status["_417_ExpectationFailed"] = 417] = "_417_ExpectationFailed";
71
+ Status[Status["_418_IMATeapot"] = 418] = "_418_IMATeapot";
72
+ Status[Status["_421_MisdirectedRequest"] = 421] = "_421_MisdirectedRequest";
73
+ Status[Status["_422_UnprocessableEntity"] = 422] = "_422_UnprocessableEntity";
74
+ Status[Status["_423_Locked"] = 423] = "_423_Locked";
75
+ Status[Status["_424_FailedDependency"] = 424] = "_424_FailedDependency";
76
+ Status[Status["_425_TooEarly"] = 425] = "_425_TooEarly";
77
+ Status[Status["_426_UpgradeRequired"] = 426] = "_426_UpgradeRequired";
78
+ Status[Status["_428_PreconditionRequired"] = 428] = "_428_PreconditionRequired";
79
+ Status[Status["_429_TooManyRequests"] = 429] = "_429_TooManyRequests";
80
+ Status[Status["_431_RequestHeaderFieldsTooLarge"] = 431] = "_431_RequestHeaderFieldsTooLarge";
81
+ Status[Status["_451_UnavailableForLegalReasons"] = 451] = "_451_UnavailableForLegalReasons";
82
+ Status[Status["_500_InternalServerError"] = 500] = "_500_InternalServerError";
83
+ Status[Status["_501_NotImplemented"] = 501] = "_501_NotImplemented";
84
+ Status[Status["_502_BadGateway"] = 502] = "_502_BadGateway";
85
+ Status[Status["_503_ServiceUnavailable"] = 503] = "_503_ServiceUnavailable";
86
+ Status[Status["_504_GatewayTimeout"] = 504] = "_504_GatewayTimeout";
87
+ Status[Status["_505_HTTPVersionNotSupported"] = 505] = "_505_HTTPVersionNotSupported";
88
+ Status[Status["_506_VariantAlsoNegotiates"] = 506] = "_506_VariantAlsoNegotiates";
89
+ Status[Status["_507_InsufficientStorage"] = 507] = "_507_InsufficientStorage";
90
+ Status[Status["_508_LoopDetected"] = 508] = "_508_LoopDetected";
91
+ Status[Status["_510_NotExtended"] = 510] = "_510_NotExtended";
92
+ Status[Status["_511_NetworkAuthenticationRequired"] = 511] = "_511_NetworkAuthenticationRequired";
93
+ Status[Status["_419_PageExpired"] = 419] = "_419_PageExpired";
94
+ Status[Status["_420_EnhanceYourCalm"] = 420] = "_420_EnhanceYourCalm";
95
+ Status[Status["_450_BlockedbyWindowsParentalControls"] = 450] = "_450_BlockedbyWindowsParentalControls";
96
+ Status[Status["_498_InvalidToken"] = 498] = "_498_InvalidToken";
97
+ Status[Status["_499_TokenRequired"] = 499] = "_499_TokenRequired";
98
+ Status[Status["_509_BandwidthLimitExceeded"] = 509] = "_509_BandwidthLimitExceeded";
99
+ Status[Status["_526_InvalidSSLCertificate"] = 526] = "_526_InvalidSSLCertificate";
100
+ Status[Status["_529_Siteisoverloaded"] = 529] = "_529_Siteisoverloaded";
101
+ Status[Status["_530_Siteisfrozen"] = 530] = "_530_Siteisfrozen";
102
+ Status[Status["_598_NetworkReadTimeoutError"] = 598] = "_598_NetworkReadTimeoutError";
103
+ Status[Status["_599_NetworkConnectTimeoutError"] = 599] = "_599_NetworkConnectTimeoutError";
104
+ })(Status || (exports.Status = Status = {}));
29
105
  function getHttpStatusText(code) {
30
106
  switch (code) {
31
107
  // 1xx Informational
@@ -239,8 +315,12 @@ const redirect = (location, init) => {
239
315
  };
240
316
  exports.redirect = redirect;
241
317
  /**
242
- * Forwards the request to another handler internally.
243
- * Does not change the URL or send a redirect to the client.
318
+ * Forwards the request to another route internally.
319
+ * Does not send a redirect to the client but changes the path and method,
320
+ * adds X-Forwarded-[Method|Path] and X-Original-Path headers and calls
321
+ * `(this as Router).respond(newReq, ctx)`.
322
+ * NOTE: parse body only once at the first handler using `parseBody({once: true})`
323
+ * as the body will be consumed at the first parseBody call.
244
324
  * @param {string} path - The new path to forward to
245
325
  * @returns {Response} A Response object with the forwarded request's response
246
326
  */
@@ -248,13 +328,19 @@ const forward = (path, options) => {
248
328
  return function (req, ctx) {
249
329
  return __awaiter(this, void 0, void 0, function* () {
250
330
  var _a;
331
+ const method = (_a = options === null || options === void 0 ? void 0 : options.method) !== null && _a !== void 0 ? _a : req.method;
332
+ const headers = new Headers(req.headers);
333
+ const body = req.body ? yield req.clone().arrayBuffer() : undefined;
251
334
  const url = new URL(req.url);
335
+ const originalPathname = url.pathname;
252
336
  url.pathname = path;
253
- const newReq = new Request(url.toString(), {
254
- method: (_a = options === null || options === void 0 ? void 0 : options.method) !== null && _a !== void 0 ? _a : req.method,
255
- headers: req.headers,
256
- body: req.body ? req.clone().body : undefined,
257
- });
337
+ if (method != req.method)
338
+ headers.set("X-Forwarded-Method", req.method);
339
+ headers.set("X-Forwarded-Path", originalPathname);
340
+ if (!req.headers.has("X-Original-Path")) {
341
+ headers.set("X-Original-Path", originalPathname);
342
+ }
343
+ const newReq = new Request(url.toString(), { method, headers, body });
258
344
  return this.respond(newReq, ctx);
259
345
  });
260
346
  };
@@ -559,89 +645,6 @@ const parseCookieFromRequest = (req) => {
559
645
  return undefined;
560
646
  };
561
647
  exports.parseCookieFromRequest = parseCookieFromRequest;
562
- /**
563
- * Creates middleware that parses cookies from the request and adds them to the context.
564
- * @returns {Function} A middleware function that adds parsed cookies to context.cookie
565
- * @example
566
- * const cookieParser = parseCookie();
567
- * // Use in respondWith: respondWith({}, cookieParser(), ...otherHandlers)
568
- */
569
- const parseCookie = () => {
570
- return (req, ctx) => {
571
- var _a;
572
- const cookie = (_a = (0, exports.parseCookieFromRequest)(req)) !== null && _a !== void 0 ? _a : {};
573
- ctx.cookie = cookie;
574
- };
575
- };
576
- exports.parseCookie = parseCookie;
577
- /**
578
- * Creates middleware that parses the request body based on Content-Type.
579
- * Supports url-encoded forms, JSON, and plain text.
580
- * @param {Object} [options] - Configuration options for body parsing
581
- * @param {SupportedBodyMediaTypes|SupportedBodyMediaTypes[]} [options.accept] - Media types to accept (defaults to all supported)
582
- * @param {number} [options.maxSize] - Maximum body size in bytes (defaults to 1MB)
583
- * @returns {Function} A middleware function that adds parsed body to context.body
584
- * @throws {Response} Returns a 415 response if content-type is not accepted
585
- * @throws {Response} Returns a 413 response if body exceeds maxSize
586
- * @throws {Response} Returns a 400 response if body is malformed
587
- * @example
588
- * const bodyParser = parseBody({ maxSize: 5000 });
589
- * // Use in respondWith: respondWith({}, bodyParser(), ...otherHandlers)
590
- */
591
- const parseBody = (options) => {
592
- var _a;
593
- const accept = (options === null || options === void 0 ? void 0 : options.accept)
594
- ? Array.isArray(options.accept)
595
- ? options.accept
596
- : [options.accept]
597
- : [
598
- "application/x-www-form-urlencoded",
599
- "application/json",
600
- "text/plain",
601
- ];
602
- const maxSize = (_a = options === null || options === void 0 ? void 0 : options.maxSize) !== null && _a !== void 0 ? _a : 1024 * 1024; // Default 1MB
603
- return (req, ctx) => __awaiter(void 0, void 0, void 0, function* () {
604
- var _a, _b, _c, _d;
605
- const contentType = (_a = req.headers.get("content-type")) === null || _a === void 0 ? void 0 : _a.split(";", 2)[0];
606
- if (!(contentType && accept.includes(contentType))) {
607
- yield ((_b = req.body) === null || _b === void 0 ? void 0 : _b.cancel().catch(() => { }));
608
- return (0, exports.status)(415);
609
- }
610
- try {
611
- const contentLengthHeader = req.headers.get("content-length");
612
- if (!contentLengthHeader || parseInt(contentLengthHeader) > maxSize) {
613
- yield ((_c = req.body) === null || _c === void 0 ? void 0 : _c.cancel().catch(() => { }));
614
- return (0, exports.status)(413);
615
- }
616
- switch (contentType) {
617
- case "application/x-www-form-urlencoded": {
618
- const body = yield req.formData();
619
- ctx.body = Object.fromEntries(body.entries());
620
- break;
621
- }
622
- case "application/json": {
623
- const body = yield req.json();
624
- ctx.body =
625
- typeof body === "object" ? body : {};
626
- break;
627
- }
628
- case "text/plain": {
629
- const text = yield req.text();
630
- ctx.body = { text };
631
- break;
632
- }
633
- default:
634
- ctx.body = {};
635
- break;
636
- }
637
- }
638
- catch (_e) {
639
- yield ((_d = req.body) === null || _d === void 0 ? void 0 : _d.cancel().catch(() => { }));
640
- return (0, exports.status)(400, "Malformed Payload");
641
- }
642
- });
643
- };
644
- exports.parseBody = parseBody;
645
648
  /**
646
649
  * Creates a request handler that processes requests through a series of middleware/handlers.
647
650
  * Handlers are executed in order. If a handler returns a Response, that response is returned immediately.