itty-router 4.0.0-next.49 → 4.0.0-next.52
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 +66 -31
- package/Router.d.ts +28 -21
- package/Router.js +1 -1
- package/cjs/Router.d.ts +28 -21
- package/cjs/Router.js +1 -1
- package/cjs/index.js +1 -1
- package/index.js +1 -1
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -1,31 +1,69 @@
|
|
|
1
|
-
# [](https://itty-router.dev)
|
|
2
1
|
|
|
3
|
-
[](https://npmjs.com/package/itty-router)
|
|
4
|
-
[](https://bundlephobia.com/result?p=itty-router)
|
|
5
|
-
[](https://github.com/kwhitley/itty-router/actions/workflows/verify.yml)
|
|
6
|
-
[](https://coveralls.io/github/kwhitley/itty-router?branch=v4.x)
|
|
7
|
-
[](https://npmjs.com/package/itty-router)
|
|
8
|
-
[](https://github.com/kwhitley/itty-router/issues)
|
|
9
2
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://itty.dev/itty-router">
|
|
5
|
+
<img src="https://user-images.githubusercontent.com/865416/146679767-16be95b4-5dd7-4bcf-aed7-b8aa8c828f48.png" alt="Itty Router" />
|
|
6
|
+
</a>
|
|
7
|
+
<p>
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
<h3 align="center"><a href="https://itty.dev/itty-router">4.x Documentation @ itty.dev</a></h3>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://npmjs.com/package/itty-router" target="_blank">
|
|
14
|
+
<img src="https://img.shields.io/npm/v/itty-router.svg?style=flat-square" alt="npm version" />
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://bundlephobia.com/result?p=itty-router" target="_blank">
|
|
17
|
+
<img src="https://img.shields.io/bundlephobia/minzip/itty-router?style=flat-square" alt="bundle size" />
|
|
18
|
+
</a>
|
|
19
|
+
<a href="https://github.com/kwhitley/itty-router/actions/workflows/verify.yml" target="_blank">
|
|
20
|
+
<img src="https://img.shields.io/github/actions/workflow/status/kwhitley/itty-router/verify.yml?branch=v4.x&style=flat-square" alt="build status" />
|
|
21
|
+
</a>
|
|
22
|
+
<a href="https://coveralls.io/github/kwhitley/itty-router?branch=v4.x" target="_blank">
|
|
23
|
+
<img src="https://img.shields.io/coveralls/github/kwhitley/itty-router/v4.x?style=flat-square" alt="code coverage" />
|
|
24
|
+
</a>
|
|
25
|
+
<a href="https://npmjs.com/package/itty-router" target="_blank">
|
|
26
|
+
<img src="https://img.shields.io/npm/dw/itty-router?style=flat-square" alt="weekly downloads" />
|
|
27
|
+
</a>
|
|
28
|
+
<a href="https://github.com/kwhitley/itty-router/issues" target="_blank">
|
|
29
|
+
<img src="https://img.shields.io/github/issues/kwhitley/itty-router?style=flat-square" alt="open issues" />
|
|
30
|
+
</a>
|
|
31
|
+
<a href="" target="_blank">
|
|
32
|
+
<img src="" alt="" />
|
|
33
|
+
</a>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<a href="https://discord.com/channels/832353585802903572" target="_blank">
|
|
38
|
+
<img src="https://img.shields.io/discord/832353585802903572?style=flat-square" alt="join us on discord" />
|
|
39
|
+
</a>
|
|
40
|
+
<a href="https://github.com/kwhitley/itty-router" target="_blank">
|
|
41
|
+
<img src="https://img.shields.io/github/stars/kwhitley/itty-router?style=social" alt="repo stars" />
|
|
42
|
+
</a>
|
|
43
|
+
<a href="https://www.twitter.com/kevinrwhitley" target="_blank">
|
|
44
|
+
<img src="https://img.shields.io/twitter/follow/kevinrwhitley.svg?style=social&label=Follow" alt="follow the author" />
|
|
45
|
+
</a>
|
|
46
|
+
<a href="" target="_blank">
|
|
47
|
+
<img src="" alt="" />
|
|
48
|
+
</a>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
Itty aims to be the world's smallest (~440 bytes), feature-rich JavaScript router, enabling beautiful API code with a near-zero bundlesize. Designed originally for [Cloudflare Workers](https://itty.dev/itty-router/runtimes#Cloudflare%20Workers), itty can be used in browsers, Service Workers, edge functions, or standalone runtimes like [Node](https://itty.dev/itty-router/runtimes#Node), [Bun](https://itty.dev/itty-router/runtimes#Bun), etc.!
|
|
15
54
|
|
|
16
55
|
## Features:
|
|
56
|
+
- [fully typed/TypeScript support](https://itty.dev/itty-router#typescript)
|
|
17
57
|
- [route params](https://itty.dev/itty-router/route-patterns#params) (including [optional params](https://itty.dev/itty-router/route-patterns#optional))
|
|
18
58
|
- [wildcards](https://itty.dev/itty-router/route-patterns#wildcards) and [greedy params](https://itty.dev/itty-router/route-patterns#greedy)
|
|
19
59
|
- [query parsing](https://itty.dev/itty-router/route-patterns#query)
|
|
20
60
|
- [middleware](https://itty.dev/itty-router/middleware)
|
|
21
61
|
- [router nesting](https://itty.dev/itty-router/nesting)
|
|
22
|
-
- any real/fake HTTP method
|
|
23
62
|
- lightweight, easy-to-understand route code
|
|
24
|
-
- works in *any* runtime/environment (including the browser)
|
|
25
|
-
- fully typed/TS
|
|
63
|
+
- works in virtually [*any* runtime/environment](https://itty.dev/itty-router/runtimes) (including the browser)
|
|
26
64
|
|
|
27
65
|
## [Full Documentation](https://itty.dev/itty-router)
|
|
28
|
-
Complete docs/API available
|
|
66
|
+
Complete docs/API are available at [itty.dev](https://itty.dev/itty-router), or join our [Discord](https://discord.com/channels/832353585802903572) channel to chat!
|
|
29
67
|
|
|
30
68
|
## Installation
|
|
31
69
|
```
|
|
@@ -35,20 +73,17 @@ npm install itty-router@next
|
|
|
35
73
|
## Example
|
|
36
74
|
```js
|
|
37
75
|
import {
|
|
38
|
-
error, //
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
withParams, // middleware to auto-embed route params
|
|
43
|
-
notFound, // create a 404
|
|
76
|
+
error, // creates error responses
|
|
77
|
+
json, // creates json responses
|
|
78
|
+
Router, // the ~440 byte router itself
|
|
79
|
+
withParams, // middleware: puts params directly on the Request
|
|
44
80
|
} from 'itty-router'
|
|
45
81
|
|
|
46
82
|
const router = Router() // create a new Router
|
|
47
83
|
const todos = [] // and some fake todos
|
|
48
84
|
|
|
49
85
|
router
|
|
50
|
-
//
|
|
51
|
-
// withParams auto-parses route params into the request
|
|
86
|
+
// middleware: withParams auto-parses route params into the request
|
|
52
87
|
.all('*', withParams)
|
|
53
88
|
|
|
54
89
|
// GET list of todos
|
|
@@ -57,18 +92,18 @@ router
|
|
|
57
92
|
// GET single todo, by ID
|
|
58
93
|
.get('/todos/:id',
|
|
59
94
|
({ id }) => todos.find(todo => todo.id === id)
|
|
60
|
-
||
|
|
95
|
+
|| error(404, 'That todo was not found')
|
|
61
96
|
)
|
|
62
97
|
|
|
63
98
|
// 404 for everything else
|
|
64
|
-
.all('*',
|
|
99
|
+
.all('*', () => error(404))
|
|
65
100
|
|
|
66
|
-
// Example: Cloudflare
|
|
101
|
+
// Example: Cloudflare Worker module syntax
|
|
67
102
|
export default {
|
|
68
|
-
fetch: (request,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
103
|
+
fetch: (request, ...args) => router
|
|
104
|
+
.handle(request, ...args)
|
|
105
|
+
.then(json) // automatically send as JSON
|
|
106
|
+
.catch(error) // and send error Responses for thrown errors
|
|
72
107
|
}
|
|
73
108
|
```
|
|
74
109
|
|
package/Router.d.ts
CHANGED
|
@@ -5,9 +5,10 @@ export declare type RequestLike = {
|
|
|
5
5
|
method: string;
|
|
6
6
|
url: string;
|
|
7
7
|
} & GenericTraps;
|
|
8
|
-
export declare type
|
|
8
|
+
export declare type IRequestStrict = {
|
|
9
9
|
method: string;
|
|
10
10
|
url: string;
|
|
11
|
+
route: string;
|
|
11
12
|
params: {
|
|
12
13
|
[key: string]: string;
|
|
13
14
|
};
|
|
@@ -15,28 +16,34 @@ export declare type IRequest = {
|
|
|
15
16
|
[key: string]: string | string[] | undefined;
|
|
16
17
|
};
|
|
17
18
|
proxy?: any;
|
|
18
|
-
} &
|
|
19
|
-
export
|
|
19
|
+
} & Request;
|
|
20
|
+
export declare type IRequest = IRequestStrict & GenericTraps;
|
|
21
|
+
export declare type RouterOptions = {
|
|
20
22
|
base?: string;
|
|
21
23
|
routes?: RouteEntry[];
|
|
22
|
-
}
|
|
23
|
-
export
|
|
24
|
-
(request:
|
|
25
|
-
}
|
|
24
|
+
};
|
|
25
|
+
export declare type RouteHandler<I = IRequest, A extends any[] = any[]> = {
|
|
26
|
+
(request: I, ...args: A): any;
|
|
27
|
+
};
|
|
26
28
|
export declare type RouteEntry = [string, RegExp, RouteHandler[], string];
|
|
27
|
-
export declare type Route = <
|
|
28
|
-
export declare type
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
options: Route;
|
|
33
|
-
patch: Route;
|
|
34
|
-
post: Route;
|
|
35
|
-
put: Route;
|
|
29
|
+
export declare type Route = <RequestType = IRequest, Args extends any[] = any[], RT = RouterType>(path: string, ...handlers: RouteHandler<RequestType, Args>[]) => RT;
|
|
30
|
+
export declare type UniversalRoute<RequestType = IRequest, Args extends any[] = any[]> = (path: string, ...handlers: RouteHandler<RequestType, Args>[]) => RouterType<UniversalRoute<RequestType, Args>, Args>;
|
|
31
|
+
declare type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
|
|
32
|
+
export declare type CustomRoutes<R = Route> = {
|
|
33
|
+
[key: string]: R;
|
|
36
34
|
};
|
|
37
|
-
export declare type RouterType = {
|
|
38
|
-
__proto__: RouterType
|
|
35
|
+
export declare type RouterType<R = Route, Args extends any[] = any[]> = {
|
|
36
|
+
__proto__: RouterType<R>;
|
|
39
37
|
routes: RouteEntry[];
|
|
40
|
-
handle: (request: RequestLike, ...extra:
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
handle: <A extends any[] = Args>(request: RequestLike, ...extra: Equal<R, Args> extends true ? A : Args) => Promise<any>;
|
|
39
|
+
all: R;
|
|
40
|
+
delete: R;
|
|
41
|
+
get: R;
|
|
42
|
+
head: R;
|
|
43
|
+
options: R;
|
|
44
|
+
patch: R;
|
|
45
|
+
post: R;
|
|
46
|
+
put: R;
|
|
47
|
+
} & CustomRoutes<R>;
|
|
48
|
+
export declare const Router: <RequestType = IRequest, Args extends any[] = any[], RouteType = Equal<RequestType, IRequest> extends true ? Route : UniversalRoute<RequestType, Args>>({ base, routes }?: RouterOptions) => RouterType<RouteType, Args>;
|
|
49
|
+
export {};
|
package/Router.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=({base:e="",routes:r=[]}={})=>({__proto__:new Proxy({},{get:(a,o,t,p)=>(a,...l)=>r.push([o.toUpperCase(),RegExp(`^${(p=e+"/"+a).replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),l,p])&&t}),routes:r,async handle(e,...a){let o,t,p=new URL(e.url),l=e.query={};for(let[e,r]of p.searchParams)l[e]=void 0===l[e]?r:[l[e],r].flat();for(let[l,s
|
|
1
|
+
const e=({base:e="",routes:r=[]}={})=>({__proto__:new Proxy({},{get:(a,o,t,p)=>(a,...l)=>r.push([o.toUpperCase(),RegExp(`^${(p=(e+"/"+a).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),l,p])&&t}),routes:r,async handle(e,...a){let o,t,p=new URL(e.url),l=e.query={};for(let[e,r]of p.searchParams)l[e]=void 0===l[e]?r:[l[e],r].flat();for(let[l,s,$,c]of r)if((l===e.method||"ALL"===l)&&(t=p.pathname.match(s))){e.params=t.groups||{},e.route=c;for(let r of $)if(void 0!==(o=await r(e.proxy||e,...a)))return o}}});export{e as Router};
|
package/cjs/Router.d.ts
CHANGED
|
@@ -5,9 +5,10 @@ export declare type RequestLike = {
|
|
|
5
5
|
method: string;
|
|
6
6
|
url: string;
|
|
7
7
|
} & GenericTraps;
|
|
8
|
-
export declare type
|
|
8
|
+
export declare type IRequestStrict = {
|
|
9
9
|
method: string;
|
|
10
10
|
url: string;
|
|
11
|
+
route: string;
|
|
11
12
|
params: {
|
|
12
13
|
[key: string]: string;
|
|
13
14
|
};
|
|
@@ -15,28 +16,34 @@ export declare type IRequest = {
|
|
|
15
16
|
[key: string]: string | string[] | undefined;
|
|
16
17
|
};
|
|
17
18
|
proxy?: any;
|
|
18
|
-
} &
|
|
19
|
-
export
|
|
19
|
+
} & Request;
|
|
20
|
+
export declare type IRequest = IRequestStrict & GenericTraps;
|
|
21
|
+
export declare type RouterOptions = {
|
|
20
22
|
base?: string;
|
|
21
23
|
routes?: RouteEntry[];
|
|
22
|
-
}
|
|
23
|
-
export
|
|
24
|
-
(request:
|
|
25
|
-
}
|
|
24
|
+
};
|
|
25
|
+
export declare type RouteHandler<I = IRequest, A extends any[] = any[]> = {
|
|
26
|
+
(request: I, ...args: A): any;
|
|
27
|
+
};
|
|
26
28
|
export declare type RouteEntry = [string, RegExp, RouteHandler[], string];
|
|
27
|
-
export declare type Route = <
|
|
28
|
-
export declare type
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
options: Route;
|
|
33
|
-
patch: Route;
|
|
34
|
-
post: Route;
|
|
35
|
-
put: Route;
|
|
29
|
+
export declare type Route = <RequestType = IRequest, Args extends any[] = any[], RT = RouterType>(path: string, ...handlers: RouteHandler<RequestType, Args>[]) => RT;
|
|
30
|
+
export declare type UniversalRoute<RequestType = IRequest, Args extends any[] = any[]> = (path: string, ...handlers: RouteHandler<RequestType, Args>[]) => RouterType<UniversalRoute<RequestType, Args>, Args>;
|
|
31
|
+
declare type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
|
|
32
|
+
export declare type CustomRoutes<R = Route> = {
|
|
33
|
+
[key: string]: R;
|
|
36
34
|
};
|
|
37
|
-
export declare type RouterType = {
|
|
38
|
-
__proto__: RouterType
|
|
35
|
+
export declare type RouterType<R = Route, Args extends any[] = any[]> = {
|
|
36
|
+
__proto__: RouterType<R>;
|
|
39
37
|
routes: RouteEntry[];
|
|
40
|
-
handle: (request: RequestLike, ...extra:
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
handle: <A extends any[] = Args>(request: RequestLike, ...extra: Equal<R, Args> extends true ? A : Args) => Promise<any>;
|
|
39
|
+
all: R;
|
|
40
|
+
delete: R;
|
|
41
|
+
get: R;
|
|
42
|
+
head: R;
|
|
43
|
+
options: R;
|
|
44
|
+
patch: R;
|
|
45
|
+
post: R;
|
|
46
|
+
put: R;
|
|
47
|
+
} & CustomRoutes<R>;
|
|
48
|
+
export declare const Router: <RequestType = IRequest, Args extends any[] = any[], RouteType = Equal<RequestType, IRequest> extends true ? Route : UniversalRoute<RequestType, Args>>({ base, routes }?: RouterOptions) => RouterType<RouteType, Args>;
|
|
49
|
+
export {};
|
package/cjs/Router.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";exports.Router=({base:e="",routes:r=[]}={})=>({__proto__:new Proxy({},{get:(a,o,t,p)=>(a,...
|
|
1
|
+
"use strict";exports.Router=({base:e="",routes:r=[]}={})=>({__proto__:new Proxy({},{get:(a,o,t,p)=>(a,...s)=>r.push([o.toUpperCase(),RegExp(`^${(p=(e+"/"+a).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),s,p])&&t}),routes:r,async handle(e,...a){let o,t,p=new URL(e.url),s=e.query={};for(let[e,r]of p.searchParams)s[e]=void 0===s[e]?r:[s[e],r].flat();for(let[s,l,u,$]of r)if((s===e.method||"ALL"===s)&&(t=p.pathname.match(l))){e.params=t.groups||{},e.route=$;for(let r of u)if(void 0!==(o=await r(e.proxy||e,...a)))return o}}});
|
package/cjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";class e extends Error{status;constructor(e=500,t){"object"==typeof t?(super(t.error),Object.assign(this,t)):super(t),this.status=e}}const t=(e="text/plain; charset=utf-8",t)=>(s,r={})=>{const{headers:o={},...n}=r;return"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...o},...n})},s=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"),o=t("text/html"),n=t("image/jpeg"),a=t("image/png"),c=t("image/webp");exports.Router=({base:e="",routes:t=[]}={})=>({__proto__:new Proxy({},{get:(s,r,o,n)=>(s,...a)=>t.push([r.toUpperCase(),RegExp(`^${(n=e+"/"+s).replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),a,n])&&o}),routes:t,async handle(e,...s){let r,o,n=new URL(e.url),a=e.query={};for(let[e,t]of n.searchParams)a[e]=void 0===a[e]?t:[a[e],t].flat();for(let[a,c,p,l]of t)if((a===e.method||"ALL"===a)&&(o=n.pathname.match(c))){e.params=o.groups||{},e.route=l
|
|
1
|
+
"use strict";class e extends Error{status;constructor(e=500,t){"object"==typeof t?(super(t.error),Object.assign(this,t)):super(t),this.status=e}}const t=(e="text/plain; charset=utf-8",t)=>(s,r={})=>{const{headers:o={},...n}=r;return"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...o},...n})},s=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"),o=t("text/html"),n=t("image/jpeg"),a=t("image/png"),c=t("image/webp");exports.Router=({base:e="",routes:t=[]}={})=>({__proto__:new Proxy({},{get:(s,r,o,n)=>(s,...a)=>t.push([r.toUpperCase(),RegExp(`^${(n=(e+"/"+s).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),a,n])&&o}),routes:t,async handle(e,...s){let r,o,n=new URL(e.url),a=e.query={};for(let[e,t]of n.searchParams)a[e]=void 0===a[e]?t:[a[e],t].flat();for(let[a,c,p,l]of t)if((a===e.method||"ALL"===a)&&(o=n.pathname.match(c))){e.params=o.groups||{},e.route=l;for(let t of p)if(void 0!==(r=await t(e.proxy||e,...s)))return r}}}),exports.StatusError=e,exports.createCors=(e={})=>{const{origins:t=["*"],maxAge:s,methods:r=["GET"],headers:o={}}=e;let n;const a={"content-type":"application/json","Access-Control-Allow-Methods":r.join(", "),...o};s&&(a["Access-Control-Max-Age"]=s);return{corsify:e=>{if(!e)throw new Error("No fetch handler responded and no upstream to proxy to specified.");const{headers:t,status:s,body:r}=e;if([101,301,302,308].includes(s))return e;const o=Object.fromEntries(t);return o["access-control-allow-origin"]?e:new Response(r,{status:s,headers:{...o,...a,...n,"content-type":t.get("content-type")}})},preflight:e=>{const s=[...new Set(["OPTIONS",...r])],o=e.headers.get("origin")||"";if(n=(t.includes(o)||t.includes("*"))&&{"Access-Control-Allow-Origin":o},"OPTIONS"===e.method){if(null!==e.headers.get("Origin")&&null!==e.headers.get("Access-Control-Request-Method")&&null!==e.headers.get("Access-Control-Request-Headers")){const t={...a,"Access-Control-Allow-Methods":s.join(", "),"Access-Control-Allow-Headers":e.headers.get("Access-Control-Request-Headers"),...n};return new Response(null,{headers:t})}return new Response(null,{headers:{Allow:s.join(", ")}})}}}},exports.createResponse=t,exports.error=(e=500,t)=>{if(e instanceof Error){const{message:s,...o}=e;e=e.status||500,t={error:s||r(e),...o}}return t={status:e,..."object"==typeof t?t:{error:t||r(e)}},s(t,{status:e})},exports.html=o,exports.jpeg=n,exports.json=s,exports.png=a,exports.status=e=>new Response(null,{status:e}),exports.text=(e,t)=>new Response(e,t),exports.webp=c,exports.withContent=async e=>{e.headers.get("content-type")?.includes("json")&&(e.content=await e.json())},exports.withCookies=e=>{e.cookies=(e.headers.get("Cookie")||"").split(/;\s*/).map((e=>e.split(/=(.+)/))).reduce(((e,[t,s])=>(e[t]=s,e)),{})},exports.withParams=e=>{e.proxy=new Proxy(e.proxy||e,{get:(t,s)=>{let r;return void 0!==(r=t[s])?r.bind?.(e)||r:t?.params?.[s]}})};
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=({base:e="",routes:t=[]}={})=>({__proto__:new Proxy({},{get:(s,r,
|
|
1
|
+
const e=({base:e="",routes:t=[]}={})=>({__proto__:new Proxy({},{get:(s,o,r,n)=>(s,...a)=>t.push([o.toUpperCase(),RegExp(`^${(n=(e+"/"+s).replace(/\/+(\/|$)/g,"$1")).replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`),a,n])&&r}),routes:t,async handle(e,...s){let o,r,n=new URL(e.url),a=e.query={};for(let[e,t]of n.searchParams)a[e]=void 0===a[e]?t:[a[e],t].flat();for(let[a,c,l,i]of t)if((a===e.method||"ALL"===a)&&(r=n.pathname.match(c))){e.params=r.groups||{},e.route=i;for(let t of l)if(void 0!==(o=await t(e.proxy||e,...s)))return o}}});class t extends Error{status;constructor(e=500,t){"object"==typeof t?(super(t.error),Object.assign(this,t)):super(t),this.status=e}}const s=(e="text/plain; charset=utf-8",t)=>(s,o={})=>{const{headers:r={},...n}=o;return"Response"===s?.constructor.name?s:new Response(t?t(s):s,{headers:{"content-type":e,...r},...n})},o=s("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"),n=(e=500,t)=>{if(e instanceof Error){const{message:s,...o}=e;e=e.status||500,t={error:s||r(e),...o}}return t={status:e,..."object"==typeof t?t:{error:t||r(e)}},o(t,{status:e})},a=e=>new Response(null,{status:e}),c=(e,t)=>new Response(e,t),l=s("text/html"),i=s("image/jpeg"),p=s("image/png"),u=s("image/webp"),d=async e=>{e.headers.get("content-type")?.includes("json")&&(e.content=await e.json())},h=e=>{e.cookies=(e.headers.get("Cookie")||"").split(/;\s*/).map((e=>e.split(/=(.+)/))).reduce(((e,[t,s])=>(e[t]=s,e)),{})},g=e=>{e.proxy=new Proxy(e.proxy||e,{get:(t,s)=>{let o;return void 0!==(o=t[s])?o.bind?.(e)||o:t?.params?.[s]}})},f=(e={})=>{const{origins:t=["*"],maxAge:s,methods:o=["GET"],headers:r={}}=e;let n;const a={"content-type":"application/json","Access-Control-Allow-Methods":o.join(", "),...r};s&&(a["Access-Control-Max-Age"]=s);return{corsify:e=>{if(!e)throw new Error("No fetch handler responded and no upstream to proxy to specified.");const{headers:t,status:s,body:o}=e;if([101,301,302,308].includes(s))return e;const r=Object.fromEntries(t);return r["access-control-allow-origin"]?e:new Response(o,{status:s,headers:{...r,...a,...n,"content-type":t.get("content-type")}})},preflight:e=>{const s=[...new Set(["OPTIONS",...o])],r=e.headers.get("origin")||"";if(n=(t.includes(r)||t.includes("*"))&&{"Access-Control-Allow-Origin":r},"OPTIONS"===e.method){if(null!==e.headers.get("Origin")&&null!==e.headers.get("Access-Control-Request-Method")&&null!==e.headers.get("Access-Control-Request-Headers")){const t={...a,"Access-Control-Allow-Methods":s.join(", "),"Access-Control-Allow-Headers":e.headers.get("Access-Control-Request-Headers"),...n};return new Response(null,{headers:t})}return new Response(null,{headers:{Allow:s.join(", ")}})}}}};export{e as Router,t as StatusError,f as createCors,s as createResponse,n as error,l as html,i as jpeg,o as json,p as png,a as status,c as text,u as webp,d as withContent,h as withCookies,g as withParams};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itty-router",
|
|
3
|
-
"version": "4.0.0-next.
|
|
3
|
+
"version": "4.0.0-next.52",
|
|
4
4
|
"description": "Tiny, zero-dependency API router - built for Cloudflare Workers, but works everywhere!",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -16,9 +16,6 @@
|
|
|
16
16
|
"nested"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"docs:dev": "cp README.md ./docs/pages/README.md && vite",
|
|
20
|
-
"docs:build": "cp README.md ./docs/pages/README.md && vite build",
|
|
21
|
-
"docs:serve": "vite preview",
|
|
22
19
|
"lint": "npx eslint src",
|
|
23
20
|
"test": "vitest --coverage --reporter verbose",
|
|
24
21
|
"test:once": "vitest run",
|
|
@@ -31,7 +28,9 @@
|
|
|
31
28
|
"build:core": "rollup -c",
|
|
32
29
|
"build:extras": "rollup --config rollup.config.extras.mjs",
|
|
33
30
|
"build": "rollup -c",
|
|
34
|
-
"release": "release --tag --push --type=next --src=dist"
|
|
31
|
+
"release": "release --tag --push --type=next --src=dist",
|
|
32
|
+
"runtime:bun": "bun example/bun.ts",
|
|
33
|
+
"runtime:node": "node example/node.js"
|
|
35
34
|
},
|
|
36
35
|
"repository": {
|
|
37
36
|
"type": "git",
|
|
@@ -49,8 +48,10 @@
|
|
|
49
48
|
"@rollup/plugin-terser": "^0.2.1",
|
|
50
49
|
"@rollup/plugin-typescript": "^10.0.1",
|
|
51
50
|
"@skypack/package-check": "^0.2.2",
|
|
51
|
+
"@types/node": "^20.2.1",
|
|
52
52
|
"@vitejs/plugin-vue": "^2.2.4",
|
|
53
53
|
"@vitest/coverage-c8": "^0.24.3",
|
|
54
|
+
"@whatwg-node/server": "^0.7.6",
|
|
54
55
|
"coveralls": "^3.1.1",
|
|
55
56
|
"eslint": "^8.11.0",
|
|
56
57
|
"eslint-plugin-jest": "^26.1.2",
|
|
@@ -58,17 +59,19 @@
|
|
|
58
59
|
"fs-extra": "^10.0.1",
|
|
59
60
|
"globby": "^13.1.3",
|
|
60
61
|
"gzip-size": "^6.0.0",
|
|
62
|
+
"http": "^0.0.1-security",
|
|
61
63
|
"isomorphic-fetch": "^3.0.0",
|
|
64
|
+
"itty-router": "^4.0.0-next.50",
|
|
62
65
|
"jsdom": "^20.0.1",
|
|
63
66
|
"npm-run-all": "^4.1.5",
|
|
64
67
|
"rimraf": "^3.0.2",
|
|
65
68
|
"rollup": "^3.8.1",
|
|
66
69
|
"rollup-plugin-bundle-size": "^1.0.3",
|
|
67
70
|
"rollup-plugin-multi-input": "^1.3.3",
|
|
71
|
+
"ts-node": "^10.9.1",
|
|
68
72
|
"typescript": "^4.8.4",
|
|
69
73
|
"vite": "^2.8.6",
|
|
70
74
|
"vitest": "^0.24.3",
|
|
71
|
-
"vue": "^3.2.31",
|
|
72
75
|
"yarn": "^1.22.18",
|
|
73
76
|
"yarn-release": "^1.10.3"
|
|
74
77
|
}
|