Socket
Socket
Sign inDemoInstall

itty-router

Package Overview
Dependencies
0
Maintainers
2
Versions
264
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.3.0-next.0 to 4.3.0-next.1

IttyRouter.d.ts

7

AutoRouter.d.ts

@@ -1,9 +0,8 @@

import { RouterOptions } from './Router';
import { RouteHandler } from 'IttyRouter';
import { ResponseFormatter } from './createResponse';
import { ResponseHandler, RouterOptions } from './Router';
type AutoRouterOptions = {
missing?: RouteHandler;
format?: ResponseFormatter;
format?: ResponseHandler;
} & RouterOptions;
export declare const AutoRouter: ({ format, missing, after, before, ...options }?: AutoRouterOptions) => import("./Router").RouterType<import("IttyRouter").Route, any[]>;
export declare const AutoRouter: ({ format, missing, finally: f, before, ...options }?: AutoRouterOptions) => import("./Router").RouterType<import("IttyRouter").Route, any[]>;
export {};

@@ -1,2 +0,2 @@

"use strict";const r=((r="text/plain; charset=utf-8",e)=>(o,{headers:t={},...a}={})=>void 0===o||"Response"===o?.constructor.name?o:new Response(e?e(o):o,{headers:{"content-type":r,...t.entries?Object.fromEntries(t):t},...a}))("application/json; charset=utf-8",JSON.stringify),e=r=>({400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"}[r]||"Unknown Error"),o=(o=500,t)=>{if(o instanceof Error){const{message:r,...a}=o;o=o.status||500,t={error:r||e(o),...a}}return t={status:o,..."object"==typeof t?t:{error:t||e(o)}},r(t,{status:o})},t=r=>{r.proxy=new Proxy(r.proxy||r,{get:(e,o)=>void 0!==e[o]?e[o].bind?.(r)||e[o]:e?.params?.[o]})};exports.AutoRouter=({format:e=r,missing:a=(()=>o(404)),after:n=[],before:s=[],...f}={})=>(({base:r="",routes:e=[],...o}={})=>({__proto__:new Proxy({},{get:(o,t,a,n)=>"handle"==t?a.fetch:(o,...s)=>e.push([t.toUpperCase?.(),RegExp(`^${(n=(r+o).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),s,n])&&a}),routes:e,...o,async fetch(r,...t){let a,n,s=new URL(r.url),f=r.query={__proto__:null};for(let[r,e]of s.searchParams)f[r]=f[r]?[].concat(f[r],e):e;r:try{for(let e of o.before||[])if(null!=(a=await e(r.proxy??r,...t)))break r;e:for(let[o,f,p,c]of e)if((o==r.method||"ALL"==o)&&(n=s.pathname.match(f))){r.params=n.groups||{},r.route=c;for(let e of p)if(null!=(a=await e(r.proxy??r,...t)))break e}}catch(e){if(!o.onError)throw e;for(let n of o.onError)a=await n(a??e,r.proxy??r,...t)??a}for(let e of o.after||[])a=await e(a,r.proxy??r,...t)??a;return a}}))({before:[t,...s],onError:[o],after:[(r,...e)=>r??a(r,...e),e,...n],...f});
"use strict";const e=((e="text/plain; charset=utf-8",r)=>(t,{...o}={})=>{if(void 0===t||t instanceof Response)return t;const a=new Response(r?.(t)??t,o);return a.headers.set("content-type",e),a})("application/json; charset=utf-8",JSON.stringify),r=e=>({400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"}[e]||"Unknown Error"),t=(t=500,o)=>{if(t instanceof Error){const{message:e,...a}=t;t=t.status||500,o={error:e||r(t),...a}}return o={status:t,..."object"==typeof o?o:{error:o||r(t)}},e(o,{status:t})},o=e=>{e.proxy=new Proxy(e.proxy||e,{get:(r,t)=>void 0!==r[t]?r[t].bind?.(e)||r[t]:r?.params?.[t]})};exports.AutoRouter=({format:r=e,missing:a=(()=>t(404)),finally:n=[],before:s=[],...c}={})=>(({base:e="",routes:r=[],...t}={})=>({__proto__:new Proxy({},{get:(t,o,a,n)=>"handle"==o?a.fetch:(t,...s)=>r.push([o.toUpperCase?.(),RegExp(`^${(n=(e+t).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),s,n])&&a}),routes:r,...t,async fetch(e,...o){let a,n,s=new URL(e.url),c=e.query={__proto__:null};for(let[e,r]of s.searchParams)c[e]=c[e]?[].concat(c[e],r):r;e:try{for(let r of t.before||[])if(null!=(a=await r(e.proxy??e,...o)))break e;r:for(let[t,c,f,i]of r)if((t==e.method||"ALL"==t)&&(n=s.pathname.match(c))){e.params=n.groups||{},e.route=i;for(let r of f)if(null!=(a=await r(e.proxy??e,...o)))break r}}catch(r){if(!t.catch)throw r;a=await t.catch(r,e.proxy??e,...o)}try{for(let r of t.finally||[])a=await r(a,e.proxy??e,...o)??a}catch(r){if(!t.catch)throw r;a=await t.catch(r,e.proxy??e,...o)}return a}}))({before:[o,...s],catch:t,finally:[(e,...r)=>e??a(e,...r),r,...n],...c});
//# sourceMappingURL=AutoRouter.js.map

@@ -1,2 +0,2 @@

"use strict";exports.createResponse=(e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...r}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...r});
"use strict";exports.createResponse=(e="text/plain; charset=utf-8",t)=>(s,{...n}={})=>{if(void 0===s||s instanceof Response)return s;const r=new Response(t?.(s)??s,n);return r.headers.set("content-type",e),r};
//# sourceMappingURL=createResponse.js.map

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",r)=>(t,{headers:s={},...n}={})=>void 0===t||"Response"===t?.constructor.name?t:new Response(r?r(t):t,{headers:{"content-type":e,...s.entries?Object.fromEntries(s):s},...n}))("application/json; charset=utf-8",JSON.stringify),r=e=>({400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"}[e]||"Unknown Error");exports.error=(t=500,s)=>{if(t instanceof Error){const{message:e,...n}=t;t=t.status||500,s={error:e||r(t),...n}}return s={status:t,..."object"==typeof s?s:{error:s||r(t)}},e(s,{status:t})};
"use strict";const r=((r="text/plain; charset=utf-8",t)=>(e,{...n}={})=>{if(void 0===e||e instanceof Response)return e;const s=new Response(t?.(e)??e,n);return s.headers.set("content-type",r),s})("application/json; charset=utf-8",JSON.stringify),t=r=>({400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"}[r]||"Unknown Error");exports.error=(e=500,n)=>{if(e instanceof Error){const{message:r,...s}=e;e=e.status||500,n={error:r||t(e),...s}}return n={status:e,..."object"==typeof n?n:{error:n||t(e)}},r(n,{status:e})};
//# sourceMappingURL=error.js.map

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...r}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...r}))("text/html");exports.html=e;
"use strict";const t=((t="text/plain; charset=utf-8",e)=>(s,{...n}={})=>{if(void 0===s||s instanceof Response)return s;const o=new Response(e?.(s)??s,n);return o.headers.set("content-type",t),o})("text/html");exports.html=t;
//# sourceMappingURL=html.js.map

@@ -1,2 +0,2 @@

"use strict";const e=({base:e="",routes:t=[],...r}={})=>({__proto__:new Proxy({},{get:(r,o,s,n)=>"handle"==o?s.fetch:(r,...a)=>t.push([o.toUpperCase?.(),RegExp(`^${(n=(e+r).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),a,n])&&s}),routes:t,...r,async fetch(e,...o){let s,n,a=new URL(e.url),c=e.query={__proto__:null};for(let[e,t]of a.searchParams)c[e]=c[e]?[].concat(c[e],t):t;e:try{for(let t of r.before||[])if(null!=(s=await t(e.proxy??e,...o)))break e;t:for(let[r,c,p,l]of t)if((r==e.method||"ALL"==r)&&(n=a.pathname.match(c))){e.params=n.groups||{},e.route=l;for(let t of p)if(null!=(s=await t(e.proxy??e,...o)))break t}}catch(t){if(!r.onError)throw t;for(let n of r.onError)s=await n(s??t,e.proxy??e,...o)??s}for(let t of r.after||[])s=await t(s,e.proxy??e,...o)??s;return s}}),t=(e="text/plain; charset=utf-8",t)=>(r,{headers:o={},...s}={})=>void 0===r||"Response"===r?.constructor.name?r:new Response(t?t(r):r,{headers:{"content-type":e,...o.entries?Object.fromEntries(o):o},...s}),r=t("application/json; charset=utf-8",JSON.stringify),o=e=>({400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"}[e]||"Unknown Error"),s=(e=500,t)=>{if(e instanceof Error){const{message:r,...s}=e;e=e.status||500,t={error:r||o(e),...s}}return t={status:e,..."object"==typeof t?t:{error:t||o(e)}},r(t,{status:e})},n=e=>{e.proxy=new Proxy(e.proxy||e,{get:(t,r)=>void 0!==t[r]?t[r].bind?.(e)||t[r]:t?.params?.[r]})};class a extends Error{status;constructor(e=500,t){super("object"==typeof t?t.error:t),"object"==typeof t&&Object.assign(this,t),this.status=e}}const c=t("text/plain; charset=utf-8",String),p=t("text/html"),l=t("image/jpeg"),i=t("image/png"),u=t("image/webp");exports.AutoRouter=({format:t=r,missing:o=(()=>s(404)),after:a=[],before:c=[],...p}={})=>e({before:[n,...c],onError:[s],after:[(e,...t)=>e??o(e,...t),t,...a],...p}),exports.IttyRouter=({base:e="",routes:t=[],...r}={})=>({__proto__:new Proxy({},{get:(r,o,s,n)=>(r,...a)=>t.push([o.toUpperCase?.(),RegExp(`^${(n=(e+r).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),a,n])&&s}),routes:t,...r,async fetch(e,...r){let o,s,n=new URL(e.url),a=e.query={__proto__:null};for(let[e,t]of n.searchParams)a[e]=a[e]?[].concat(a[e],t):t;for(let[a,c,p,l]of t)if((a==e.method||"ALL"==a)&&(s=n.pathname.match(c))){e.params=s.groups||{},e.route=l;for(let t of p)if(null!=(o=await t(e.proxy??e,...r)))return o}}}),exports.Router=e,exports.StatusError=a,exports.createCors=(e={})=>{const{origins:t=["*"],maxAge:r,methods:o=["GET"],headers:s={}}=e;let n;const a="function"==typeof t?t:e=>t.includes(e)||t.includes("*"),c={"content-type":"application/json","Access-Control-Allow-Methods":o.join(", "),...s};r&&(c["Access-Control-Max-Age"]=r);return{corsify:e=>{if(!e)throw new Error("No fetch handler responded and no upstream to proxy to specified.");const{headers:t,status:r,body:o}=e;return[101,301,302,308].includes(r)||t.get("access-control-allow-origin")?e:new Response(o,{status:r,headers:{...Object.fromEntries(t),...c,...n,"content-type":t.get("content-type")}})},preflight:e=>{const t=[...new Set(["OPTIONS",...o])],r=e.headers.get("origin")||"";if(n=a(r)&&{"Access-Control-Allow-Origin":r},"OPTIONS"===e.method){const r={...c,"Access-Control-Allow-Methods":t.join(", "),"Access-Control-Allow-Headers":e.headers.get("Access-Control-Request-Headers"),...n};return new Response(null,{headers:e.headers.get("Origin")&&e.headers.get("Access-Control-Request-Method")&&e.headers.get("Access-Control-Request-Headers")?r:{Allow:t.join(", ")}})}}}},exports.createResponse=t,exports.error=s,exports.html=p,exports.jpeg=l,exports.json=r,exports.png=i,exports.status=(e,t)=>new Response(null,{...t,status:e}),exports.text=c,exports.webp=u,exports.withContent=async e=>{e.content=await e.clone().json().catch((()=>e.clone().formData())).catch((()=>e.text()))},exports.withCookies=e=>{e.cookies=(e.headers.get("Cookie")||"").split(/;\s*/).map((e=>e.split(/=(.+)/))).reduce(((e,[t,r])=>r?(e[t]=r,e):e),{})},exports.withParams=n;
"use strict";const e=({base:e="",routes:t=[],...o}={})=>({__proto__:new Proxy({},{get:(o,r,s,a)=>"handle"==r?s.fetch:(o,...n)=>t.push([r.toUpperCase?.(),RegExp(`^${(a=(e+o).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),n,a])&&s}),routes:t,...o,async fetch(e,...r){let s,a,n=new URL(e.url),c=e.query={__proto__:null};for(let[e,t]of n.searchParams)c[e]=c[e]?[].concat(c[e],t):t;e:try{for(let t of o.before||[])if(null!=(s=await t(e.proxy??e,...r)))break e;t:for(let[o,c,p,l]of t)if((o==e.method||"ALL"==o)&&(a=n.pathname.match(c))){e.params=a.groups||{},e.route=l;for(let t of p)if(null!=(s=await t(e.proxy??e,...r)))break t}}catch(t){if(!o.catch)throw t;s=await o.catch(t,e.proxy??e,...r)}try{for(let t of o.finally||[])s=await t(s,e.proxy??e,...r)??s}catch(t){if(!o.catch)throw t;s=await o.catch(t,e.proxy??e,...r)}return s}}),t=(e="text/plain; charset=utf-8",t)=>(o,{...r}={})=>{if(void 0===o||o instanceof Response)return o;const s=new Response(t?.(o)??o,r);return s.headers.set("content-type",e),s},o=t("application/json; charset=utf-8",JSON.stringify),r=e=>({400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"}[e]||"Unknown Error"),s=(e=500,t)=>{if(e instanceof Error){const{message:o,...s}=e;e=e.status||500,t={error:o||r(e),...s}}return t={status:e,..."object"==typeof t?t:{error:t||r(e)}},o(t,{status:e})},a=e=>{e.proxy=new Proxy(e.proxy||e,{get:(t,o)=>void 0!==t[o]?t[o].bind?.(e)||t[o]:t?.params?.[o]})};class n extends Error{status;constructor(e=500,t){super("object"==typeof t?t.error:t),"object"==typeof t&&Object.assign(this,t),this.status=e}}const c=t("text/plain; charset=utf-8",String),p=t("text/html"),l=t("image/jpeg"),i=t("image/png"),u=t("image/webp");exports.AutoRouter=({format:t=o,missing:r=(()=>s(404)),finally:n=[],before:c=[],...p}={})=>e({before:[a,...c],catch:s,finally:[(e,...t)=>e??r(e,...t),t,...n],...p}),exports.IttyRouter=({base:e="",routes:t=[],...o}={})=>({__proto__:new Proxy({},{get:(o,r,s,a)=>(o,...n)=>t.push([r.toUpperCase?.(),RegExp(`^${(a=(e+o).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),n,a])&&s}),routes:t,...o,async fetch(e,...o){let r,s,a=new URL(e.url),n=e.query={__proto__:null};for(let[e,t]of a.searchParams)n[e]=n[e]?[].concat(n[e],t):t;for(let[n,c,p,l]of t)if((n==e.method||"ALL"==n)&&(s=a.pathname.match(c))){e.params=s.groups||{},e.route=l;for(let t of p)if(null!=(r=await t(e.proxy??e,...o)))return r}}}),exports.Router=e,exports.StatusError=n,exports.createCors=(e={})=>{const{origins:t=["*"],maxAge:o,methods:r=["GET"],headers:s={}}=e;let a;const n="function"==typeof t?t:e=>t.includes(e)||t.includes("*"),c={"content-type":"application/json","Access-Control-Allow-Methods":r.join(", "),...s};o&&(c["Access-Control-Max-Age"]=o);return{corsify:e=>{if(!e)throw new Error("No fetch handler responded and no upstream to proxy to specified.");const{headers:t,status:o,body:r}=e;return[101,301,302,308].includes(o)||t.get("access-control-allow-origin")?e:new Response(r,{status:o,headers:{...Object.fromEntries(t),...c,...a,"content-type":t.get("content-type")}})},preflight:e=>{const t=[...new Set(["OPTIONS",...r])],o=e.headers.get("origin")||"";if(a=n(o)&&{"Access-Control-Allow-Origin":o},"OPTIONS"===e.method){const o={...c,"Access-Control-Allow-Methods":t.join(", "),"Access-Control-Allow-Headers":e.headers.get("Access-Control-Request-Headers"),...a};return new Response(null,{headers:e.headers.get("Origin")&&e.headers.get("Access-Control-Request-Method")&&e.headers.get("Access-Control-Request-Headers")?o:{Allow:t.join(", ")}})}}}},exports.createResponse=t,exports.error=s,exports.html=p,exports.jpeg=l,exports.json=o,exports.png=i,exports.status=(e,t)=>new Response(null,{...t,status:e}),exports.text=c,exports.webp=u,exports.withContent=async e=>{e.content=await e.clone().json().catch((()=>e.clone().formData())).catch((()=>e.text()))},exports.withCookies=e=>{e.cookies=(e.headers.get("Cookie")||"").split(/;\s*/).map((e=>e.split(/=(.+)/))).reduce(((e,[t,o])=>o?(e[t]=o,e):e),{})},exports.withParams=a;
//# sourceMappingURL=index.js.map

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...r}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...r}))("image/jpeg");exports.jpeg=e;
"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{...n}={})=>{if(void 0===s||s instanceof Response)return s;const o=new Response(t?.(s)??s,n);return o.headers.set("content-type",e),o})("image/jpeg");exports.jpeg=e;
//# sourceMappingURL=jpeg.js.map

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...o}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...o}))("application/json; charset=utf-8",JSON.stringify);exports.json=e;
"use strict";const t=((t="text/plain; charset=utf-8",e)=>(s,{...n}={})=>{if(void 0===s||s instanceof Response)return s;const o=new Response(e?.(s)??s,n);return o.headers.set("content-type",t),o})("application/json; charset=utf-8",JSON.stringify);exports.json=t;
//# sourceMappingURL=json.js.map
{
"name": "itty-router",
"version": "4.3.0-next.0",
"version": "4.3.0-next.1",
"description": "A tiny, zero-dependency router, designed to make beautiful APIs in any environment.",

@@ -5,0 +5,0 @@ "main": "./index.js",

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...r}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...r}))("image/png");exports.png=e;
"use strict";const e=((e="text/plain; charset=utf-8",t)=>(n,{...s}={})=>{if(void 0===n||n instanceof Response)return n;const o=new Response(t?.(n)??n,s);return o.headers.set("content-type",e),o})("image/png");exports.png=e;
//# sourceMappingURL=png.js.map
<p align="center">
<a href="https://itty.dev/itty-router">
<img src="https://github.com/kwhitley/itty-router/assets/865416/15a90b05-344d-4135-a3f8-52a4d117250e" alt="Itty Router" />
<img src="https://github.com/kwhitley/itty-router/assets/865416/319e4148-0a2d-4396-b18b-9e1cbb8e27b6" alt="Itty Router" />
</a>
<br /><br />
<p>
<h2 align="center"><a href="https://itty.dev/itty-router">v4.x Documentation @ itty.dev</a>
<br /></h2>
<p align="center">

@@ -29,8 +27,5 @@ <a href="https://npmjs.com/package/itty-router" target="_blank">

</a>
<a href="" target="_blank">
<img src="" alt="" />
</a>
</p>
<p align="center">
<br />
<a href="https://discord.gg/53vyrZAu9u" target="_blank">

@@ -42,4 +37,4 @@ <img src="https://img.shields.io/discord/832353585802903572?label=Discord&logo=Discord&style=flat-square&logoColor=fff" alt="join us on discord" />

</a>
<a href="https://www.twitter.com/kevinrwhitley" target="_blank">
<img src="https://img.shields.io/twitter/follow/kevinrwhitley.svg?style=social&label=Follow" alt="follow the author" />
<a href="https://www.twitter.com/ittydev" target="_blank">
<img src="https://img.shields.io/twitter/follow/ittydev.svg?style=social&label=Follow" alt="follow ittydev" />
</a>

@@ -53,177 +48,37 @@ <a href="" target="_blank">

Itty is arguably the smallest (~460 bytes) feature-rich JavaScript router available, while enabling dead-simple API code.
An ultra-tiny API microrouter, for use when [size matters](https://github.com/TigersWay/cloudflare-playground) (e.g. [Cloudflare Workers](https://developers.cloudflare.com/workers/)).
Designed originally for [Cloudflare Workers](https://itty.dev/itty-router/runtimes#Cloudflare%20Workers), itty can be used in browsers, service workers, edge functions, or runtimes like [Node](https://itty.dev/itty-router/runtimes#Node), [Bun](https://itty.dev/itty-router/runtimes#Bun), etc.!
## Features
- Tiny. [~460](https://deno.bundlejs.com/?q=itty-router/Router) bytes for the Router itself, or [~1.6k](https://bundlephobia.com/package/itty-router) for the entire library (>100x smaller than [express.js](https://www.npmjs.com/package/express)).
- [Fully-Typed](https://itty.dev/itty-router/typescript).
- Shorter, simpler route code than most modern routers.
- Dead-simple [middleware](https://itty.dev/itty-router/middleware) - use ours or write your own.
- Supports [nested APIs](https://itty.dev/itty-router/nesting).
- Platform agnostic (based on [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)) - use it [anywhere, in any environment](https://itty.dev/itty-router/runtimes).
- Parses [route params](https://itty.dev/itty-router/route-patterns#params),
[optional params](https://itty.dev/itty-router/route-patterns#optional),
[wildcards](https://itty.dev/itty-router/route-patterns#wildcards),
[greedy params](https://itty.dev/itty-router/route-patterns#greedy),
[file formats](https://itty.dev/itty-router/route-patterns#file-formats)
and [query strings](https://itty.dev/itty-router/route-patterns#query).
- Extremely extendable/flexible. We leave you in complete control.
- Tiny. We have routers from [~450 bytes](https://itty.dev/itty-router/routers/ittyrouter) to a [~1kB bytes](https://itty.dev/itty-router/routers/autorouter) batteries-included version. For comparison, [express.js](https://www.npmjs.com/package/express) is over 200x as large.
- Web Standards - Use it [anywhere, in any environment](https://itty.dev/itty-router/runtimes).
- No assumptions. Return anything you like, pass in any arguments you like.
- Future-proof. HTTP methods not-yet-invented already work with it.
- [Route-parsing](https://itty.dev/itty-router/route-patterns) & [query parsing](https://itty.dev/itty-router/route-patterns#query).
- [Middleware](https://itty.dev/itty-router/middleware) - use ours or write your own.
- [Nesting](https://itty.dev/itty-router/nesting).
## [Full Documentation](https://itty.dev/itty-router)
## Example (Cloudflare Worker or Bun)
Complete API documentation is available at [itty.dev/itty-router](https://itty.dev/itty-router), or join our [Discord](https://discord.gg/53vyrZAu9u) channel to chat with community members for quick help!
## Installation
```
npm install itty-router
```
## Example
```js
import {
error, // creates error responses
json, // creates JSON responses
Router, // the ~440 byte router itself
withParams, // middleware: puts params directly on the Request
} from 'itty-router'
import { todos } from './external/todos'
import { AutoRouter } from 'itty-router' // ~1kB
// create a new Router
const router = Router()
export default AutoRouter()
.get('/hello/:name', ({ name }) => `Hello, ${name}!`)
.get('/json', () => [1,2,3])
.get('/promises', () => Promise.resolve('foo'))
router
// add some middleware upstream on all routes
.all('*', withParams)
// GET list of todos
.get('/todos', () => todos)
// GET single todo, by ID
.get(
'/todos/:id',
({ id }) => todos.getById(id) || error(404, 'That todo was not found')
)
// 404 for everything else
.all('*', () => error(404))
// Example: Cloudflare Worker module syntax
export default {
fetch: (request, ...args) =>
router
.handle(request, ...args)
.then(json) // send as JSON
.catch(error), // catch errors
}
// that's it ^-^
```
# What's different about itty? <a name="a-different-kind-of-router"></a>
Itty does a few things very differently from other routers. This allows itty route code to be shorter and more intuitive than most!
# [Full Documentation](https://itty.dev/itty-router) @ [itty.dev](https://itty.dev)
### 1. Simpler handler/middleware flow.
In itty, you simply return (anything) to exit the flow. If any handler ever returns a thing, that's what the `router.handle` returns. If it doesn't, it's considered middleware, and the next handler is called.
Complete API documentation is available at [itty.dev/itty-router](https://itty.dev/itty-router), or join our [Discord](https://discord.gg/53vyrZAu9u) channel to chat with community members for quick help!
That's it!
```ts
// not middleware: any handler that returns (anything at all)
(request) => [1, 4, 5, 1]
// middleware: simply doesn't return
const withUser = (request) => {
request.user = 'Halsey'
}
// a middleware that *might* return
const onlyHalsey = (request) => {
if (request.user !== 'Halsey') {
return error(403, 'Only Halsey is allowed to see this!')
}
}
// uses middleware, then returns something
route.get('/secure', withUser, onlyHalsey,
({ user }) => `Hey, ${user} - welcome back!`
)
```
### 2. You don't have to build a response in each route handler.
We've been stuck in this pattern for over a decade. Almost every router still expects you to build and return a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)... in every single route.
We think you should be able to do that once, at the end. In most modern APIs for instance, we're serving JSON in the majority of our routes. So why handle that more than once?
```ts
router
// we can still do it the manual way
.get('/traditional', (request) => json([1, 2, 3]))
// or defer to later
.get('/easy-mode', (request) => [1, 2, 3])
// later, when handling a request
router
.handle(request)
.then(json) // we can turn any non-Response into valid JSON.
```
### 3. It's all Promises.
itty `await`s every handler, looking for a return value. If it gets one, it breaks the flow and returns the value. If it doesn't, it continues processing handlers/routes until it does. This means that every handler can either be synchronous or async - it's all the same.
When paired with the fact that we can simply return raw data and transform it later, this is AWESOME for working with async APIs, database layers, etc. We don't need to transform anything at the route, we can simply return the Promise (to data) itself!
Check this out:
```ts
import { myDatabase } from './somewhere'
router
// assumes getItems() returns a Promise to some data
.get('/items', () => myDatabase.getItems())
// later, when handling a request
router
.handle(request)
.then(json) // we can turn any non-Response into valid JSON.
```
### 4. Only one required argument. The rest is up to you.
itty only requires one argument - a Request-like object with the following shape: `{ url, method }` (usually a native [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)). Because itty is not opinionated about [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) creation, there is not "response" argument built in. Every other argument you pass to `route.handle` is given to each handler, in the same order.
> ### This makes itty one of the most platform-agnostic routers, *period*, as it's able to match up to any platform's signature.
Here's an example using [Cloudflare Worker](https://workers.cloudflare.com/) arguments:
```ts
router
.get('/my-route', (request, environment, context) => {
// we can access anything here that was passed to `router.handle`.
})
// Cloudflare gives us 3 arguments: request, environment, and context.
// Passing them to `route.handle` gives every route handler (above) access to each.
export default {
fetch: (request, env, ctx) => router
.handle(request, env, ctx)
.then(json)
.catch(error)
}
```
## Join the Discussion!
Have a question? Suggestion? Complaint? Want to send a gift basket?
Have a question? Suggestion? Idea? Complaint? Want to send a gift basket?
Join us on [Discord](https://discord.gg/53vyrZAu9u)!
## Testing and Contributing
1. Fork repo
1. Install dev dependencies via `yarn`
1. Start test runner/dev mode `yarn dev`
1. Add your code and tests if needed - do NOT remove/alter existing tests
1. Commit files
1. Submit PR (and fill out the template)
1. I'll add you to the credits! :)
## Special Thanks: Contributors

@@ -250,2 +105,3 @@

- [@jahands](https://github.com/jahands) - v4.x TS fixes
- and many, many others

@@ -252,0 +108,0 @@ #### Documentation

import { Equal, IRequest, IttyRouterOptions, IttyRouterType, Route, RouteHandler, UniversalRoute } from './IttyRouter';
export type ResponseHandler<ResponseType = any, RequestType = IRequest, Args extends any[] = any[]> = (response: ResponseType, request: RequestType, ...args: Args) => any;
export type ErrorHandler<ErrorOrResponse = Error, RequestType = IRequest, Args extends any[] = any[]> = (response: ErrorOrResponse, request: RequestType, ...args: Args) => any;
export type ErrorHandler<ErrorType = Error, RequestType = IRequest, Args extends any[] = any[]> = (response: ErrorType, request: RequestType, ...args: Args) => any;
export type RouterType<R = Route, Args extends any[] = any[]> = {
before?: RouteHandler[];
onError?: ErrorHandler[];
after?: ResponseHandler[];
catch?: ErrorHandler;
finally?: ResponseHandler[];
} & IttyRouterType<R, Args>;
export type RouterOptions = {
before?: RouteHandler[];
onError?: ErrorHandler[];
after?: ResponseHandler[];
catch?: ErrorHandler;
finally?: ResponseHandler[];
} & IttyRouterOptions;
export declare const Router: <RequestType = IRequest, Args extends any[] = any[], RouteType = Equal<RequestType, IRequest> extends true ? Route : UniversalRoute<RequestType, Args>>({ base, routes, ...other }?: RouterOptions) => RouterType<RouteType, Args>;

@@ -1,2 +0,2 @@

"use strict";exports.Router=({base:r="",routes:e=[],...o}={})=>({__proto__:new Proxy({},{get:(o,t,a,f)=>"handle"==t?a.fetch:(o,...l)=>e.push([t.toUpperCase?.(),RegExp(`^${(f=(r+o).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),l,f])&&a}),routes:e,...o,async fetch(r,...t){let a,f,l=new URL(r.url),p=r.query={__proto__:null};for(let[r,e]of l.searchParams)p[r]=p[r]?[].concat(p[r],e):e;r:try{for(let e of o.before||[])if(null!=(a=await e(r.proxy??r,...t)))break r;e:for(let[o,p,c,s]of e)if((o==r.method||"ALL"==o)&&(f=l.pathname.match(p))){r.params=f.groups||{},r.route=s;for(let e of c)if(null!=(a=await e(r.proxy??r,...t)))break e}}catch(e){if(!o.onError)throw e;for(let f of o.onError)a=await f(a??e,r.proxy??r,...t)??a}for(let e of o.after||[])a=await e(a,r.proxy??r,...t)??a;return a}});
"use strict";exports.Router=({base:e="",routes:r=[],...t}={})=>({__proto__:new Proxy({},{get:(t,a,o,c)=>"handle"==a?o.fetch:(t,...l)=>r.push([a.toUpperCase?.(),RegExp(`^${(c=(e+t).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),l,c])&&o}),routes:r,...t,async fetch(e,...a){let o,c,l=new URL(e.url),p=e.query={__proto__:null};for(let[e,r]of l.searchParams)p[e]=p[e]?[].concat(p[e],r):r;e:try{for(let r of t.before||[])if(null!=(o=await r(e.proxy??e,...a)))break e;r:for(let[t,p,f,h]of r)if((t==e.method||"ALL"==t)&&(c=l.pathname.match(p))){e.params=c.groups||{},e.route=h;for(let r of f)if(null!=(o=await r(e.proxy??e,...a)))break r}}catch(r){if(!t.catch)throw r;o=await t.catch(r,e.proxy??e,...a)}try{for(let r of t.finally||[])o=await r(o,e.proxy??e,...a)??o}catch(r){if(!t.catch)throw r;o=await t.catch(r,e.proxy??e,...a)}return o}});
//# sourceMappingURL=Router.js.map

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...r}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...r}))("text/plain; charset=utf-8",String);exports.text=e;
"use strict";const t=((t="text/plain; charset=utf-8",e)=>(n,{...s}={})=>{if(void 0===n||n instanceof Response)return n;const r=new Response(e?.(n)??n,s);return r.headers.set("content-type",t),r})("text/plain; charset=utf-8",String);exports.text=t;
//# sourceMappingURL=text.js.map

@@ -1,2 +0,2 @@

"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...r}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...r}))("image/webp");exports.webp=e;
"use strict";const e=((e="text/plain; charset=utf-8",t)=>(s,{...n}={})=>{if(void 0===s||s instanceof Response)return s;const o=new Response(t?.(s)??s,n);return o.headers.set("content-type",e),o})("image/webp");exports.webp=e;
//# sourceMappingURL=webp.js.map

@@ -1,2 +0,2 @@

"use strict";exports.websocket=(e,t={})=>((e="text/plain; charset=utf-8",t)=>(s,{headers:n={},...o}={})=>void 0===s||"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...n.entries?Object.fromEntries(n):n},...o}))()(null,{status:101,webSocket:e,...t});
"use strict";exports.websocket=(e,t={})=>((e="text/plain; charset=utf-8",t)=>(s,{...n}={})=>{if(void 0===s||s instanceof Response)return s;const o=new Response(t?.(s)??s,n);return o.headers.set("content-type",e),o})()(null,{status:101,webSocket:e,...t});
//# sourceMappingURL=websocket.js.map

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc