bun-crumb 0.8.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 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
52
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
52
- type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 307 | 308;
53
+ type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308;
53
54
  /**
54
55
  * HTTP Header struct.
55
56
  */
@@ -58,6 +59,11 @@ type Header = {
58
59
  value: string;
59
60
  };
60
61
  type Headers = ResponseInit['headers'];
62
+
63
+ /**
64
+ *
65
+ * Type of Request search parameters
66
+ */
61
67
  type RouteRequestParams<T extends string | undefined = undefined> = [
62
68
  T
63
69
  ] extends [string] ? {
@@ -66,21 +72,16 @@ type RouteRequestParams<T extends string | undefined = undefined> = [
66
72
  [key: string]: string | undefined;
67
73
  };
68
74
  /**
69
- *
70
- *
71
75
  * Type of RouteRequest generic
72
- *
73
- *
74
- *
75
- *
76
- *
77
76
  */
78
77
  interface RouteRequestGeneric {
79
78
  body?: unknown;
80
79
  params?: string;
81
80
  }
82
81
  /**
83
- * Type of route handler `request`
82
+ *
83
+ *
84
+ * Type of route handler `request` parameter
84
85
  */
85
86
  interface RouteRequest<T extends RouteRequestGeneric = RouteRequestGeneric> extends Omit<BunRequest, 'params'> {
86
87
  params: RouteRequestParams<T['params']>;
@@ -117,9 +118,53 @@ interface RouteResponse<T extends {
117
118
  } = {
118
119
  body: unknown;
119
120
  }> {
120
- setHeader: (name: Header['name'], value: Header['value']) => void;
121
121
  send: (data: T['body'], options?: ResponseOptions) => void;
122
- redirect: (url: string, status: RedirectStatusCode | (number & {})) => void;
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;
123
168
  }
124
169
  type Route = Partial<Record<HttpMethod, RouteOptions>>;
125
170
  type RouteHandler = (request: RouteRequest, response: RouteResponse) => Promise<void> | void;
@@ -166,6 +211,7 @@ interface ListenOptions {
166
211
  *
167
212
  *
168
213
  *
214
+ *
169
215
  * @example
170
216
  *
171
217
  * ```typescript
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{serve as t}from"bun";class e extends Error{status;constructor(t,e){super(e),this.status=t,this.name="HttpError"}}const s=new Map,n=(t,s)=>n=>{const o=n.headers.get("Content-Type")??"text/plain",r=n;return r.handleBody=()=>((t,s,n,o)=>{const r={"application/json":t=>t.json().catch(()=>{throw new e(400,"Bad Request")}).then(t=>{if(n&&o&&!o(t,n))throw new e(400,"Request does not match schema");return t}),"text/plain":t=>t.text().catch(t=>{throw new e(400,t)}).then(t=>{if(n&&o&&!o(t,n))throw new e(400,"Request does not match schema");return t})};return s in r?r[s](t):Promise.reject(new e(415,"Unsupported media type"))})(n,o,t.schema,s),Promise.resolve(((t,e)=>{let s=200,n="",o="";const r={},a={setHeader:(t,e)=>{r[t]=e},send:(t,e)=>{"object"==typeof t?(r["Content-Type"]="application/json",o=JSON.stringify(t)):"string"==typeof t&&(r["Content-Type"]="text/plain",o=t),e&&(s=e.status,n=e.statusText)},redirect:(t,e)=>{o="",s=e,r.Location=t}};return Promise.resolve(e.handler(t,a)).then(()=>new Response(o,{headers:r,status:s,statusText:n}))})(r,t)).then(t=>t).catch(t=>t instanceof e?new Response(t.message,{status:t.status}):new Response("Internal server error",{status:500}))},o=(t,e)=>{const s={};for(const o in t)Object.hasOwn(t,o)&&(s[o]=n(t[o],e));return s},r=(t,e)=>{const s={};for(const n of t)s[n[0]]=o(n[1],e);return t.clear(),s},a=e=>{t({port:e?.port,hostname:e?.hostname,development:e?.development??!1,routes:r(s,e?.schemaValidator)})},c=t=>{const e=s.get(t.url);e?e[t.method]=t:s.set(t.url,{[t.method]:t})};export{c as createRoute,a as listen};
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/route';
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
@@ -1,3 +1,4 @@
1
1
  export * from './route';
2
2
  export * from './server';
3
3
  export * from './schema';
4
+ export * from './utils';
@@ -1,23 +1,10 @@
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
- * @example
7
- * ```typescript
8
- * const method: HttpMethod = 'GET';
9
- * ```
6
+ * Type of Request search parameters
10
7
  */
11
- export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
12
- export type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 307 | 308;
13
- /**
14
- * HTTP Header struct.
15
- */
16
- export type Header = {
17
- name: string;
18
- value: string;
19
- };
20
- export type Headers = ResponseInit['headers'];
21
8
  export type RouteRequestParams<T extends string | undefined = undefined> = [
22
9
  T
23
10
  ] extends [string] ? {
@@ -26,21 +13,16 @@ export type RouteRequestParams<T extends string | undefined = undefined> = [
26
13
  [key: string]: string | undefined;
27
14
  };
28
15
  /**
29
- *
30
- *
31
16
  * Type of RouteRequest generic
32
- *
33
- *
34
- *
35
- *
36
- *
37
17
  */
38
18
  export interface RouteRequestGeneric {
39
19
  body?: unknown;
40
20
  params?: string;
41
21
  }
42
22
  /**
43
- * Type of route handler `request`
23
+ *
24
+ *
25
+ * Type of route handler `request` parameter
44
26
  */
45
27
  export interface RouteRequest<T extends RouteRequestGeneric = RouteRequestGeneric> extends Omit<BunRequest, 'params'> {
46
28
  params: RouteRequestParams<T['params']>;
@@ -77,9 +59,53 @@ export interface RouteResponse<T extends {
77
59
  } = {
78
60
  body: unknown;
79
61
  }> {
80
- setHeader: (name: Header['name'], value: Header['value']) => void;
81
62
  send: (data: T['body'], options?: ResponseOptions) => void;
82
- redirect: (url: string, status: RedirectStatusCode | (number & {})) => void;
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;
83
109
  }
84
110
  export type Route = Partial<Record<HttpMethod, RouteOptions>>;
85
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'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bun-crumb",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "author": "marigold",
5
5
  "module": "dist/index.js",
6
6
  "license": "UNLICENSED",