From 6e6a771c1a7ad061d71593932e9aef768c8132a2 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Fri, 18 Mar 2022 17:57:35 +0100 Subject: [PATCH 01/13] Add env and ctx to router.handle() --- index.d.ts | 24 ++++++++++++++++++++---- index.js | 15 ++++++++++++--- package.json | 2 +- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index eeaa2bb..916ee3c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -265,16 +265,32 @@ type RouterRequest = { * HTTP request method */ method: string + /** + * Object containing request headers + */ + headers: Headers + /** + * URL String + */ + url: string + /** + * Environment object + */ + env: any + /** + * Context object + */ + ctx: any + /** + * Cloudflare object + */ + cf: any /** * Object containing all parameters defined in the url string */ params: { [key: string]: string } - /** - * Object containing request headers - */ - headers: Headers /** * Only available if method is `POST`, `PUT` or `PATCH`. Contains either the received body string or a parsed object if valid JSON was sent. */ diff --git a/index.js b/index.js index b9e6815..d82ec81 100644 --- a/index.js +++ b/index.js @@ -294,16 +294,25 @@ class Router { * Handle requests * * @param {Request} request + * @param {any} env + * @param {any} ctx * @returns {Response} */ - async handle(request) { + async handle(request, env, ctx) { try { if (request instanceof Event) { request = request.request console.warn("Warning: Using `event` on `router.handle()` is deprecated and might go away in future versions, please use `event.request` instead.") } - const req = { headers: request.headers, method: request.method, url: request.url, cf: request.cf || {} } - req.params = [] + const req = { + method: request.method, + headers: request.headers, + url: request.url, + env: env || {}, + ctx: ctx || {}, + cf: request.cf || {}, + params: [] + } if (req.method === 'OPTIONS' && Object.keys(this.corsConfig).length) { return new Response(null, { headers: { diff --git a/package.json b/package.json index e507265..1f48a58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.1.11", + "version": "1.2.0", "description": "", "main": "index.js", "scripts": {}, From 93d45905280a297758d6e937c85f83e031928f03 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Fri, 18 Mar 2022 19:37:43 +0100 Subject: [PATCH 02/13] Global middleware --- README.md | 19 ++++++++++++++++++- index.d.ts | 16 +++++++++++++++- index.js | 20 ++++++++++++++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 605b9fc..e89d4bd 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,17 @@ const router = new Router() // Enabling buildin CORS support router.cors() +// Register global middleware +router.use((req, res, next) => { + res.headers = { + ...res.headers, + 'X-Global-Middlewares': 'true' + } + next() +}) + // Simple get router.get('/user', (req, res) => { - res.body = { data: { id: 1, @@ -89,6 +97,15 @@ Enable or disable debug mode. Which will return the `error.stack` in case of an State is a `boolean` which determines if debug mode should be enabled or not (default: `true`) +### `router.use(handler) + +Register a global middleware handler. + +#### `handler` (function) + +Handler is a `function` which will be called for every request. + + ### `router.cors([config])` If enabled will overwrite other `OPTIONS` requests. diff --git a/index.d.ts b/index.d.ts index 916ee3c..d4a04c1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -14,6 +14,13 @@ declare class Router { * @type {Route[]} */ protected routes: Route[] + /** + * Global Handlers + * + * @protected + * @type {Handler[]} + */ + protected globalHandlers: Handler[] /** * Debug Mode * @@ -70,6 +77,13 @@ declare class Router { * @param {Response} response * @param {next} next */ + /** + * Register global handler + * + * @param {RouterHandler} handler + * @param handlers + */ + use(handler: RouterHandler): Router /** * Register CONNECT route * @@ -303,7 +317,7 @@ type RouterResponse = { /** * Object you can set response headers in */ - headers: Headers + headers: Object /** * Return status code (default: `204`) */ diff --git a/index.js b/index.js index d82ec81..6bc147e 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,11 @@ class Router { */ this.routes = [] + /** + * Global Handlers + */ + this.globalHandlers = [] + /** * Debug Mode * @@ -80,6 +85,16 @@ class Router { * @param {RouterNext} next */ + /** + * Register global handler + * + * @param {RouterHandler} handler + */ + use(handlers) { + this.globalHandlers.push(handlers) + return this + } + /** * Register CONNECT route * @@ -355,13 +370,14 @@ class Router { 'Access-Control-Max-Age': this.corsConfig.maxAge, } } + const handlers = [...this.globalHandlers, ...route.handlers] let prevIndex = -1 const runner = async index => { if (index === prevIndex) throw new Error('next() called multiple times') prevIndex = index - if (typeof route.handlers[index] === 'function') - await route.handlers[index](req, res, async () => await runner(index + 1)) + if (typeof handlers[index] === 'function') + await handlers[index](req, res, async () => await runner(index + 1)) } await runner(0) if (typeof res.body === 'object') { From 61a02ca9dba02f0eb7c970b9948b318498c07f7d Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Fri, 18 Mar 2022 19:38:21 +0100 Subject: [PATCH 03/13] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e89d4bd..6e513bf 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Enable or disable debug mode. Which will return the `error.stack` in case of an State is a `boolean` which determines if debug mode should be enabled or not (default: `true`) -### `router.use(handler) +### `router.use(handler)` Register a global middleware handler. From f7a236f1f2cbddfb98bf13ae97b13ad9bfffe5fb Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Fri, 18 Mar 2022 20:03:29 +0100 Subject: [PATCH 04/13] Change `router.handle(request, env, ctx)` to `router.handle(request, extend)` --- index.d.ts | 12 ++---------- index.js | 6 ++---- package.json | 2 +- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/index.d.ts b/index.d.ts index d4a04c1..bbbdde9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -288,17 +288,9 @@ type RouterRequest = { */ url: string /** - * Environment object + * Extend request object with custom properties */ - env: any - /** - * Context object - */ - ctx: any - /** - * Cloudflare object - */ - cf: any + extend: any /** * Object containing all parameters defined in the url string */ diff --git a/index.js b/index.js index 6bc147e..1958dfe 100644 --- a/index.js +++ b/index.js @@ -313,19 +313,17 @@ class Router { * @param {any} ctx * @returns {Response} */ - async handle(request, env, ctx) { + async handle(request, extend) { try { if (request instanceof Event) { request = request.request console.warn("Warning: Using `event` on `router.handle()` is deprecated and might go away in future versions, please use `event.request` instead.") } const req = { + ...extend, method: request.method, headers: request.headers, url: request.url, - env: env || {}, - ctx: ctx || {}, - cf: request.cf || {}, params: [] } if (req.method === 'OPTIONS' && Object.keys(this.corsConfig).length) { diff --git a/package.json b/package.json index 1f48a58..bea3895 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.2.0", + "version": "1.2.1", "description": "", "main": "index.js", "scripts": {}, From 14595bb2051732a415520fdabd5cbb18bbab3a1f Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Fri, 18 Mar 2022 20:35:33 +0100 Subject: [PATCH 05/13] fix --- index.d.ts | 7 ++----- index.js | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index bbbdde9..1bb1f95 100644 --- a/index.d.ts +++ b/index.d.ts @@ -218,9 +218,10 @@ declare class Router { * Handle requests * * @param {Request} request + * @param {any} extend * @returns {Response} */ - handle(request: Request): Response + handle(request: Request, extend: any): Response } declare namespace Router { export { Route, RouterRequest, RouterResponse, RouterNext, RouterHandler, RouterCorsConfig } @@ -287,10 +288,6 @@ type RouterRequest = { * URL String */ url: string - /** - * Extend request object with custom properties - */ - extend: any /** * Object containing all parameters defined in the url string */ diff --git a/index.js b/index.js index 1958dfe..ef2452f 100644 --- a/index.js +++ b/index.js @@ -309,11 +309,10 @@ class Router { * Handle requests * * @param {Request} request - * @param {any} env - * @param {any} ctx + * @param {any} extend * @returns {Response} */ - async handle(request, extend) { + async handle(request, extend = {}) { try { if (request instanceof Event) { request = request.request From 2e8703d20c6f3132d9e86ed752a366209f5a2662 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Fri, 18 Mar 2022 20:35:50 +0100 Subject: [PATCH 06/13] Update version to 1.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bea3895..af7e444 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.2.1", + "version": "1.2.2", "description": "", "main": "index.js", "scripts": {}, From be1d09dc93bd09d8efe647d435fbdba66bc07212 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 23 Mar 2022 20:48:42 +0100 Subject: [PATCH 07/13] Prepopulate request, don't parse body for DELETE method --- README.md | 1 - index.js | 6 ++++-- package.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6e513bf..4cbb206 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,6 @@ Key | Type | Description `params` | `object` | Object containing all parameters defined in the url string `query` | `object` | Object containing all query parameters - ### `res`-Object Key | Type | Description diff --git a/index.js b/index.js index ef2452f..6de9333 100644 --- a/index.js +++ b/index.js @@ -323,7 +323,9 @@ class Router { method: request.method, headers: request.headers, url: request.url, - params: [] + params: [], + query: {}, + body: '' } if (req.method === 'OPTIONS' && Object.keys(this.corsConfig).length) { return new Response(null, { @@ -336,7 +338,7 @@ class Router { status: this.corsConfig.optionsSuccessStatus }) } - if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) { + if (['POST', 'PUT', 'PATCH'].includes(req.method)) { if (req.headers.has('Content-Type') && req.headers.get('Content-Type').includes('json')) { try { req.body = await request.json() diff --git a/package.json b/package.json index af7e444..30a1ef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.2.2", + "version": "1.2.3", "description": "", "main": "index.js", "scripts": {}, From e30c9d0ded7b9588412727156e341966a966f28b Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 27 Apr 2022 18:00:59 +0200 Subject: [PATCH 08/13] Typescript fix --- index.d.ts | 4 ++-- index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 1bb1f95..772030c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -218,10 +218,10 @@ declare class Router { * Handle requests * * @param {Request} request - * @param {any} extend + * @param {any=} extend * @returns {Response} */ - handle(request: Request, extend: any): Response + handle(request: Request, extend?: any): Response } declare namespace Router { export { Route, RouterRequest, RouterResponse, RouterNext, RouterHandler, RouterCorsConfig } diff --git a/index.js b/index.js index 6de9333..71ca66a 100644 --- a/index.js +++ b/index.js @@ -309,7 +309,7 @@ class Router { * Handle requests * * @param {Request} request - * @param {any} extend + * @param {any=} extend * @returns {Response} */ async handle(request, extend = {}) { From 047878aa2c2aa47b56bc26035f37717d15c38ab8 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 27 Apr 2022 18:01:27 +0200 Subject: [PATCH 09/13] Update to 1.2.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30a1ef2..88a6a4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.2.3", + "version": "1.2.4", "description": "", "main": "index.js", "scripts": {}, From bde596e12b6ddef81fa952c4cc1365aca6439199 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 27 Apr 2022 19:41:02 +0200 Subject: [PATCH 10/13] Headers Object to Headers Object --- README.md | 9 +++------ index.d.ts | 6 +++--- index.js | 25 +++++++++++-------------- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 4cbb206..d4c86ff 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,7 @@ router.cors() // Register global middleware router.use((req, res, next) => { - res.headers = { - ...res.headers, - 'X-Global-Middlewares': 'true' - } + res.headers.set('X-Global-Middlewares', 'true') next() }) @@ -147,7 +144,7 @@ An unlimited number of functions getting [`req`](#req-object) and [`res`](#res-o Key | Type | Description --------- | ------------------- | ----------- `body` | `object` / `string` | Only available if method is `POST`, `PUT`, `PATCH` or `DELETE`. Contains either the received body string or a parsed object if valid JSON was sent. -`headers` | `object` | Object containing request headers +`headers` | `Headers` | Request [Headers Object](https://developer.mozilla.org/en-US/docs/Web/API/Headers) `method` | `string` | HTTP request method `params` | `object` | Object containing all parameters defined in the url string `query` | `object` | Object containing all query parameters @@ -157,7 +154,7 @@ Key | Type | Description Key | Type | Description --------- | ------------------- | ----------- `body` | `object` / `string` | Either set an `object` (will be converted to JSON) or a string -`headers` | `object` | Object you can set response headers in +`headers` | `Headers` | Response [Headers Object](https://developer.mozilla.org/en-US/docs/Web/API/Headers) `status` | `integer` | Return status code (default: `204`) diff --git a/index.d.ts b/index.d.ts index 772030c..bd56b54 100644 --- a/index.d.ts +++ b/index.d.ts @@ -50,7 +50,7 @@ declare class Router { * @property {string} method HTTP request method * @property {Object} params Object containing all parameters defined in the url string * @property {Object} query Object containing all query parameters - * @property {Object} headers Object containing request headers + * @property {Headers} headers Request headers object * @property {Object | string} body Only available if method is `POST`, `PUT`, `PATCH` or `DELETE`. Contains either the received body string or a parsed object if valid JSON was sent. * @property {Object} cf object containing custom Cloudflare properties. (https://developers.cloudflare.com/workers/examples/accessing-the-cloudflare-object) */ @@ -58,7 +58,7 @@ declare class Router { * Response Object * * @typedef RouterResponse - * @property {Object} headers Object you can set response headers in + * @property {Headers} headers Response headers object * @property {number} status Return status code (default: `204`) * @property {Object | string} body Either an `object` (will be converted to JSON) or a string * @property {Response} raw A response object that is to be returned, this will void all other res properties and return this as is. @@ -306,7 +306,7 @@ type RouterResponse = { /** * Object you can set response headers in */ - headers: Object + headers: Headers /** * Return status code (default: `204`) */ diff --git a/index.js b/index.js index 71ca66a..8454d75 100644 --- a/index.js +++ b/index.js @@ -54,7 +54,7 @@ class Router { * @property {string} method HTTP request method * @property {Object} params Object containing all parameters defined in the url string * @property {Object} query Object containing all query parameters - * @property {Object} headers Object containing request headers + * @property {Headers} headers Request headers object * @property {Object | string} body Only available if method is `POST`, `PUT`, `PATCH` or `DELETE`. Contains either the received body string or a parsed object if valid JSON was sent. * @property {Object} cf object containing custom Cloudflare properties. (https://developers.cloudflare.com/workers/examples/accessing-the-cloudflare-object) */ @@ -63,7 +63,7 @@ class Router { * Response Object * * @typedef RouterResponse - * @property {Object} headers Object you can set response headers in + * @property {Headers} headers Response headers object * @property {number} status Return status code (default: `204`) * @property {Object | string} body Either an `object` (will be converted to JSON) or a string * @property {Response} raw A response object that is to be returned, this will void all other res properties and return this as is. @@ -80,8 +80,8 @@ class Router { * Handler Function * * @callback RouterHandler - * @param {Request} request - * @param {Response} response + * @param {RouterRequest} request + * @param {RouterResponse} response * @param {RouterNext} next */ @@ -359,15 +359,12 @@ class Router { status: 404 }) } - const res = { headers: {} } + const res = { headers: new Headers() } if (Object.keys(this.corsConfig).length) { - res.headers = { - ...res.headers, - 'Access-Control-Allow-Origin': this.corsConfig.allowOrigin, - 'Access-Control-Allow-Methods': this.corsConfig.allowMethods, - 'Access-Control-Allow-Headers': this.corsConfig.allowHeaders, - 'Access-Control-Max-Age': this.corsConfig.maxAge, - } + res.headers.set('Access-Control-Allow-Origin', this.corsConfig.allowOrigin) + res.headers.set('Access-Control-Allow-Methods', this.corsConfig.allowMethods) + res.headers.set('Access-Control-Allow-Headers', this.corsConfig.allowHeaders) + res.headers.set('Access-Control-Max-Age', this.corsConfig.maxAge) } const handlers = [...this.globalHandlers, ...route.handlers] let prevIndex = -1 @@ -380,8 +377,8 @@ class Router { } await runner(0) if (typeof res.body === 'object') { - if (!res.headers['Content-Type']) - res.headers['Content-Type'] = 'application/json' + if (!res.headers.has('Content-Type')) + res.headers.set('Content-Type', 'application/json') res.body = JSON.stringify(res.body) } if (res.raw) { From 3e32f354a0ef4cb35938cc3cf0cf061a12beb17b Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 27 Apr 2022 19:44:37 +0200 Subject: [PATCH 11/13] Update to v1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 88a6a4b..2089ad0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.2.4", + "version": "1.3.0", "description": "", "main": "index.js", "scripts": {}, From 05d8f88fd280a5201adf4c21bc21771747013e48 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Thu, 28 Apr 2022 13:06:46 +0200 Subject: [PATCH 12/13] Typescript fix --- index.d.ts | 6 +++--- index.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index bd56b54..79724a2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -27,7 +27,7 @@ declare class Router { * @protected * @type {boolean} */ - protected debugMode: boolean + protected debugMode: boolean = false /** * CORS Config * @@ -186,9 +186,9 @@ declare class Router { /** * Debug Mode * - * @param {boolean} state Whether to turn on or off debug mode (default: true) + * @param {boolean} [state=true] Whether to turn on or off debug mode (default: true) */ - debug(state: boolean): void + debug(state?: boolean): void /** * Enable CORS support * diff --git a/index.js b/index.js index 8454d75..c7d51d1 100644 --- a/index.js +++ b/index.js @@ -221,7 +221,7 @@ class Router { /** * Debug Mode * - * @param {boolean} state Whether to turn on or off debug mode (default: true) + * @param {boolean} [state=true] Whether to turn on or off debug mode (default: true) */ debug(state = true) { this.debugMode = state From 4da8a860202065415ef48c516085733d3ef56c17 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Thu, 28 Apr 2022 13:07:06 +0200 Subject: [PATCH 13/13] Update to v1.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2089ad0..599ba48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tsndr/cloudflare-worker-router", - "version": "1.3.0", + "version": "1.3.1", "description": "", "main": "index.js", "scripts": {},