bun-crumb 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +90 -13
- package/dist/index.js +1 -1
- package/dist/server.d.ts +4 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/route.d.ts +80 -23
- package/dist/types/utils.d.ts +19 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BunRequest } from 'bun';
|
|
1
|
+
import { BunRequest, CookieInit } from 'bun';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The global Schema type that reflects schema type in `Validate` function
|
|
@@ -43,13 +43,14 @@ type Validate = (data: unknown, schema: SchemaData) => boolean;
|
|
|
43
43
|
/**
|
|
44
44
|
* HTTP Method primitive.
|
|
45
45
|
*
|
|
46
|
+
*
|
|
46
47
|
* @example
|
|
47
48
|
* ```typescript
|
|
48
49
|
* const method: HttpMethod = 'GET';
|
|
49
50
|
* ```
|
|
50
51
|
*/
|
|
51
|
-
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS';
|
|
52
|
-
type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 307 | 308;
|
|
52
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
|
53
|
+
type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308;
|
|
53
54
|
/**
|
|
54
55
|
* HTTP Header struct.
|
|
55
56
|
*/
|
|
@@ -58,16 +59,47 @@ type Header = {
|
|
|
58
59
|
value: string;
|
|
59
60
|
};
|
|
60
61
|
type Headers = ResponseInit['headers'];
|
|
62
|
+
|
|
61
63
|
/**
|
|
62
|
-
*
|
|
64
|
+
*
|
|
65
|
+
* Type of Request search parameters
|
|
63
66
|
*/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
67
|
+
type RouteRequestParams<T extends string | undefined = undefined> = [
|
|
68
|
+
T
|
|
69
|
+
] extends [string] ? {
|
|
70
|
+
[K in T]: string;
|
|
71
|
+
} : {
|
|
72
|
+
[key: string]: string | undefined;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Type of RouteRequest generic
|
|
76
|
+
*/
|
|
77
|
+
interface RouteRequestGeneric {
|
|
78
|
+
body?: unknown;
|
|
79
|
+
params?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
*
|
|
83
|
+
*
|
|
84
|
+
* Type of route handler `request` parameter
|
|
85
|
+
*/
|
|
86
|
+
interface RouteRequest<T extends RouteRequestGeneric = RouteRequestGeneric> extends Omit<BunRequest, 'params'> {
|
|
87
|
+
params: RouteRequestParams<T['params']>;
|
|
69
88
|
/**
|
|
70
|
-
*
|
|
89
|
+
* #### Parses and validates body of request.
|
|
90
|
+
*
|
|
91
|
+
* - Parses body to JSON or text
|
|
92
|
+
* - Validates body with `schemaValidator` if it is provided.
|
|
93
|
+
*
|
|
94
|
+
* @returns Promise with handled body
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
*
|
|
98
|
+
* ```typescript
|
|
99
|
+
* request.handleBody().then((bodyData) => {
|
|
100
|
+
* console.log(bodyData);
|
|
101
|
+
* })
|
|
102
|
+
* ```
|
|
71
103
|
*/
|
|
72
104
|
handleBody: () => Promise<T extends {
|
|
73
105
|
body: unknown;
|
|
@@ -86,9 +118,53 @@ interface RouteResponse<T extends {
|
|
|
86
118
|
} = {
|
|
87
119
|
body: unknown;
|
|
88
120
|
}> {
|
|
89
|
-
setHeader: (name: Header['name'], value: Header['value']) => void;
|
|
90
121
|
send: (data: T['body'], options?: ResponseOptions) => void;
|
|
91
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Sets `Location` header to provided `url` and `response.status` to provided `status`
|
|
124
|
+
*
|
|
125
|
+
*
|
|
126
|
+
*
|
|
127
|
+
* @param url `Location` to redirect
|
|
128
|
+
*
|
|
129
|
+
* @param status redirect http code (`3xx`)
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
*
|
|
133
|
+
*
|
|
134
|
+
* ```typescript
|
|
135
|
+
* return response.redirect('https://bun-crumb.vercel.app', 302);
|
|
136
|
+
* ```
|
|
137
|
+
* The same behaviour is
|
|
138
|
+
* ```typescript
|
|
139
|
+
* response.setHeader('Location', 'https://bun-crumb.vercel.app');
|
|
140
|
+
* return response.send('', {status: 302});
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
redirect: (url: string, status?: RedirectStatusCode | (number & {})) => void;
|
|
144
|
+
/**
|
|
145
|
+
* Sets the response header.
|
|
146
|
+
*
|
|
147
|
+
*
|
|
148
|
+
*
|
|
149
|
+
*
|
|
150
|
+
* Overrides header if it already exists.
|
|
151
|
+
*
|
|
152
|
+
* Case of `name` is not important. Names 'content-type', 'Content-Type', 'CoNteNt=TYPE' are the same.
|
|
153
|
+
*
|
|
154
|
+
*
|
|
155
|
+
* @param name header name
|
|
156
|
+
* @param value header value
|
|
157
|
+
*
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* response.setHeader('Access-Control-Allow-Origin', '*');
|
|
162
|
+
* // The code below will override the header above
|
|
163
|
+
* response.setHeader('access-control-allow-origin', 'https://bun-crumb.vercel.app');
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
setHeader: (name: Header['name'], value: Header['value']) => void;
|
|
167
|
+
setCookie: (options: CookieInit) => void;
|
|
92
168
|
}
|
|
93
169
|
type Route = Partial<Record<HttpMethod, RouteOptions>>;
|
|
94
170
|
type RouteHandler = (request: RouteRequest, response: RouteResponse) => Promise<void> | void;
|
|
@@ -135,6 +211,7 @@ interface ListenOptions {
|
|
|
135
211
|
*
|
|
136
212
|
*
|
|
137
213
|
*
|
|
214
|
+
*
|
|
138
215
|
* @example
|
|
139
216
|
*
|
|
140
217
|
* ```typescript
|
|
@@ -203,4 +280,4 @@ declare const listen: (options?: ListenOptions) => void;
|
|
|
203
280
|
declare const createRoute: (routeOptions: RouteOptions) => void;
|
|
204
281
|
|
|
205
282
|
export { createRoute, listen };
|
|
206
|
-
export type { Header, Headers, HttpMethod, ListenOptions, RedirectStatusCode, ResponseOptions, Route, RouteHandler, RouteOptions, RouteRequest, RouteResponse, Schema, SchemaData, Validate };
|
|
283
|
+
export type { Header, Headers, HttpMethod, ListenOptions, RedirectStatusCode, ResponseOptions, Route, RouteHandler, RouteOptions, RouteRequest, RouteRequestGeneric, RouteRequestParams, RouteResponse, Schema, SchemaData, Validate };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{serve as t}from"bun";class
|
|
1
|
+
import{serve as e,Cookie as t}from"bun";class s extends Error{status;constructor(e,t){super(t),this.status=e,this.name="HttpError"}}const n=new Map,o=(e,n)=>o=>{const r=o.headers.get("Content-Type")??"text/plain",a=o;return a.handleBody=()=>((e,t,n,o)=>{const r={"application/json":e=>e.json().catch(()=>{throw new s(400,"Bad Request")}).then(e=>{if(n&&o&&!o(e,n))throw new s(400,"Request does not match schema");return e}),"text/plain":e=>e.text().catch(e=>{throw new s(400,e)}).then(e=>{if(n&&o&&!o(e,n))throw new s(400,"Request does not match schema");return e})};return t in r?r[t](e):Promise.reject(new s(415,"Unsupported media type"))})(o,r,e.schema,n),Promise.resolve(((e,s)=>{let n=200,o="",r="";const a=new Headers,c={send:(e,t)=>{"object"==typeof e?(a.has("Content-Type")||a.set("Content-Type","application/json"),r=JSON.stringify(e)):"string"==typeof e?(a.has("Content-Type")||a.set("Content-Type","text/plain"),r=e):r=e,t&&(n=t.status,o=t.statusText)},redirect:(e,t)=>{r="",n=t||302,a.set("Location",e)},setHeader:(e,t)=>{a.set(e,t)},setCookie:e=>{a.append("Set-Cookie",new t(e).toString())}};return Promise.resolve(s.handler(e,c)).then(()=>new Response(r,{headers:a,status:n,statusText:o}))})(a,e)).then(e=>e).catch(e=>e instanceof s?new Response(e.message,{status:e.status}):new Response("Internal server error",{status:500}))},r=(e,t)=>{const s={};for(const n in e)Object.hasOwn(e,n)&&(s[n]=o(e[n],t));return s},a=(e,t)=>{const s={};for(const n of e)s[n[0]]=r(n[1],t);return e.clear(),s},c=t=>{e({port:t?.port,hostname:t?.hostname,development:t?.development??!1,routes:a(n,t?.schemaValidator)})},p=e=>{const t=n.get(e.url);t?t[e.method]=e:n.set(e.url,{[e.method]:e})};export{p as createRoute,c as listen};
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BunRequest } from 'bun';
|
|
2
|
-
import type { Route, RouteOptions, HttpMethod } from './types
|
|
2
|
+
import type { Route, RouteOptions, HttpMethod } from './types';
|
|
3
3
|
import type { SchemaData, Validate } from './types';
|
|
4
4
|
import type { ListenOptions } from './types';
|
|
5
5
|
type PreparedRoute = Partial<Record<HttpMethod, WrappedRouteCallback>>;
|
|
@@ -14,6 +14,7 @@ export type Routes = Map<RouteOptions['url'], Route>;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const _routes: Routes;
|
|
16
16
|
/**
|
|
17
|
+
*
|
|
17
18
|
* Runtime function that used in request.
|
|
18
19
|
* Parses body to supported content type (json, plain text) and validates it with route schema.
|
|
19
20
|
*
|
|
@@ -36,6 +37,7 @@ export declare const handleBody: (request: BunRequest, contentType: string, sche
|
|
|
36
37
|
*
|
|
37
38
|
*
|
|
38
39
|
* @param routeOptions options of route
|
|
40
|
+
*
|
|
39
41
|
* @returns {WrappedRouteCallback} Function that is ready to be used in Bun.serve `routes`
|
|
40
42
|
*/
|
|
41
43
|
export declare const wrapRouteCallback: (routeOptions: RouteOptions, schemaValidator?: Validate) => WrappedRouteCallback;
|
|
@@ -94,6 +96,7 @@ export declare const prepareRoutes: (routes: Routes, schemaValidator?: Validate)
|
|
|
94
96
|
*
|
|
95
97
|
*
|
|
96
98
|
*
|
|
99
|
+
*
|
|
97
100
|
* @example
|
|
98
101
|
*
|
|
99
102
|
* ```typescript
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/route.d.ts
CHANGED
|
@@ -1,33 +1,46 @@
|
|
|
1
|
-
import type { BunRequest } from 'bun';
|
|
1
|
+
import type { BunRequest, CookieInit } from 'bun';
|
|
2
2
|
import type { SchemaData } from './schema';
|
|
3
|
+
import type { Header, HttpMethod, RedirectStatusCode } from './utils';
|
|
3
4
|
/**
|
|
4
|
-
* HTTP Method primitive.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* ```typescript
|
|
8
|
-
* const method: HttpMethod = 'GET';
|
|
9
|
-
* ```
|
|
6
|
+
* Type of Request search parameters
|
|
10
7
|
*/
|
|
11
|
-
export type
|
|
12
|
-
|
|
8
|
+
export type RouteRequestParams<T extends string | undefined = undefined> = [
|
|
9
|
+
T
|
|
10
|
+
] extends [string] ? {
|
|
11
|
+
[K in T]: string;
|
|
12
|
+
} : {
|
|
13
|
+
[key: string]: string | undefined;
|
|
14
|
+
};
|
|
13
15
|
/**
|
|
14
|
-
*
|
|
16
|
+
* Type of RouteRequest generic
|
|
15
17
|
*/
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
export type Headers = ResponseInit['headers'];
|
|
18
|
+
export interface RouteRequestGeneric {
|
|
19
|
+
body?: unknown;
|
|
20
|
+
params?: string;
|
|
21
|
+
}
|
|
21
22
|
/**
|
|
22
|
-
*
|
|
23
|
+
*
|
|
24
|
+
*
|
|
25
|
+
* Type of route handler `request` parameter
|
|
23
26
|
*/
|
|
24
|
-
export interface RouteRequest<T extends {
|
|
25
|
-
|
|
26
|
-
} = {
|
|
27
|
-
body: unknown;
|
|
28
|
-
}> extends Omit<BunRequest, 'body'> {
|
|
27
|
+
export interface RouteRequest<T extends RouteRequestGeneric = RouteRequestGeneric> extends Omit<BunRequest, 'params'> {
|
|
28
|
+
params: RouteRequestParams<T['params']>;
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* #### Parses and validates body of request.
|
|
31
|
+
*
|
|
32
|
+
* - Parses body to JSON or text
|
|
33
|
+
* - Validates body with `schemaValidator` if it is provided.
|
|
34
|
+
*
|
|
35
|
+
* @returns Promise with handled body
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* request.handleBody().then((bodyData) => {
|
|
41
|
+
* console.log(bodyData);
|
|
42
|
+
* })
|
|
43
|
+
* ```
|
|
31
44
|
*/
|
|
32
45
|
handleBody: () => Promise<T extends {
|
|
33
46
|
body: unknown;
|
|
@@ -46,9 +59,53 @@ export interface RouteResponse<T extends {
|
|
|
46
59
|
} = {
|
|
47
60
|
body: unknown;
|
|
48
61
|
}> {
|
|
49
|
-
setHeader: (name: Header['name'], value: Header['value']) => void;
|
|
50
62
|
send: (data: T['body'], options?: ResponseOptions) => void;
|
|
51
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Sets `Location` header to provided `url` and `response.status` to provided `status`
|
|
65
|
+
*
|
|
66
|
+
*
|
|
67
|
+
*
|
|
68
|
+
* @param url `Location` to redirect
|
|
69
|
+
*
|
|
70
|
+
* @param status redirect http code (`3xx`)
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
*
|
|
74
|
+
*
|
|
75
|
+
* ```typescript
|
|
76
|
+
* return response.redirect('https://bun-crumb.vercel.app', 302);
|
|
77
|
+
* ```
|
|
78
|
+
* The same behaviour is
|
|
79
|
+
* ```typescript
|
|
80
|
+
* response.setHeader('Location', 'https://bun-crumb.vercel.app');
|
|
81
|
+
* return response.send('', {status: 302});
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
redirect: (url: string, status?: RedirectStatusCode | (number & {})) => void;
|
|
85
|
+
/**
|
|
86
|
+
* Sets the response header.
|
|
87
|
+
*
|
|
88
|
+
*
|
|
89
|
+
*
|
|
90
|
+
*
|
|
91
|
+
* Overrides header if it already exists.
|
|
92
|
+
*
|
|
93
|
+
* Case of `name` is not important. Names 'content-type', 'Content-Type', 'CoNteNt=TYPE' are the same.
|
|
94
|
+
*
|
|
95
|
+
*
|
|
96
|
+
* @param name header name
|
|
97
|
+
* @param value header value
|
|
98
|
+
*
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* response.setHeader('Access-Control-Allow-Origin', '*');
|
|
103
|
+
* // The code below will override the header above
|
|
104
|
+
* response.setHeader('access-control-allow-origin', 'https://bun-crumb.vercel.app');
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
setHeader: (name: Header['name'], value: Header['value']) => void;
|
|
108
|
+
setCookie: (options: CookieInit) => void;
|
|
52
109
|
}
|
|
53
110
|
export type Route = Partial<Record<HttpMethod, RouteOptions>>;
|
|
54
111
|
export type RouteHandler = (request: RouteRequest, response: RouteResponse) => Promise<void> | void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Method primitive.
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const method: HttpMethod = 'GET';
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
|
11
|
+
export type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308;
|
|
12
|
+
/**
|
|
13
|
+
* HTTP Header struct.
|
|
14
|
+
*/
|
|
15
|
+
export type Header = {
|
|
16
|
+
name: string;
|
|
17
|
+
value: string;
|
|
18
|
+
};
|
|
19
|
+
export type Headers = ResponseInit['headers'];
|