barejs 0.1.6 → 0.1.8
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 +2 -2
- package/package.json +2 -2
- package/src/bare.ts +166 -100
- package/src/context.ts +54 -0
- package/src/index.ts +15 -2
- package/src/validators.ts +55 -0
- package/src/middleware/validators.ts +0 -53
- package/src/types.ts +0 -24
package/README.md
CHANGED
|
@@ -158,8 +158,8 @@ app.post('/native', native({ properties: { id: { type: 'number' } } }), (ctx) =>
|
|
|
158
158
|
* [x] **JIT Static Routing**: lookup via compiled static maps.
|
|
159
159
|
* [x] **Validation Integration**: Support for TypeBox, Zod, and Native JSON.
|
|
160
160
|
* [x] **Full Plugin System**: Modular extensibility with zero overhead.
|
|
161
|
-
* [
|
|
162
|
-
* [
|
|
161
|
+
* [x] **Dynamic Path JIT**: Compiled Regex for parameterized routes (e.g., `/user/:id`).
|
|
162
|
+
* [x] **Native WebSocket Support**: High-speed binary streaming.
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
package/package.json
CHANGED
package/src/bare.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
json: (data: any) => Response;
|
|
5
|
-
body?: any;
|
|
6
|
-
[key: string]: any;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type Next = () => Promise<any> | any;
|
|
10
|
-
export type Middleware = (ctx: Context, next: Next) => any;
|
|
11
|
-
export type Handler = (ctx: Context) => any;
|
|
1
|
+
// src/bare.ts
|
|
2
|
+
import { BareContext } from './context';
|
|
3
|
+
import type { Context, Middleware, Handler, WSHandlers } from './context';
|
|
12
4
|
|
|
13
5
|
export interface BarePlugin {
|
|
14
6
|
name: string;
|
|
@@ -17,19 +9,50 @@ export interface BarePlugin {
|
|
|
17
9
|
}
|
|
18
10
|
|
|
19
11
|
export class BareJS {
|
|
20
|
-
private routes: { method: string; path: string; handlers:
|
|
21
|
-
private globalMiddlewares: Middleware
|
|
22
|
-
private compiledFetch?:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
12
|
+
private routes: Array<{ method: string; path: string; handlers: Array<Middleware | Handler> }> = [];
|
|
13
|
+
private globalMiddlewares: Array<Middleware> = [];
|
|
14
|
+
private compiledFetch?: Function;
|
|
15
|
+
|
|
16
|
+
private staticMap: Map<string, Function> = new Map();
|
|
17
|
+
private dynamicRoutes: Array<{
|
|
18
|
+
m: string;
|
|
19
|
+
r: RegExp;
|
|
20
|
+
p: string[];
|
|
21
|
+
c: Function;
|
|
22
|
+
}> = [];
|
|
23
|
+
|
|
24
|
+
private wsHandler: { path: string; handlers: WSHandlers } | null = null;
|
|
25
|
+
|
|
26
|
+
public get = (path: string, ...h: Array<Middleware | Handler>) => {
|
|
27
|
+
this.routes.push({ method: "GET", path, handlers: h });
|
|
28
|
+
return this;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
public post = (path: string, ...h: Array<Middleware | Handler>) => {
|
|
32
|
+
this.routes.push({ method: "POST", path, handlers: h });
|
|
33
|
+
return this;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
public put = (path: string, ...h: Array<Middleware | Handler>) => {
|
|
37
|
+
this.routes.push({ method: "PUT", path, handlers: h });
|
|
38
|
+
return this;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
public patch = (path: string, ...h: Array<Middleware | Handler>) => {
|
|
42
|
+
this.routes.push({ method: "PATCH", path, handlers: h });
|
|
43
|
+
return this;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
public delete = (path: string, ...h: Array<Middleware | Handler>) => {
|
|
47
|
+
this.routes.push({ method: "DELETE", path, handlers: h });
|
|
48
|
+
return this;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
public ws = (path: string, handlers: WSHandlers) => {
|
|
52
|
+
this.wsHandler = { path, handlers };
|
|
53
|
+
return this;
|
|
54
|
+
};
|
|
55
|
+
|
|
33
56
|
public use = (arg: Middleware | BarePlugin) => {
|
|
34
57
|
if (typeof arg === 'object' && 'install' in arg) {
|
|
35
58
|
arg.install(this);
|
|
@@ -38,91 +61,134 @@ export class BareJS {
|
|
|
38
61
|
}
|
|
39
62
|
return this;
|
|
40
63
|
};
|
|
41
|
-
|
|
42
|
-
// --- Core Engine ---
|
|
43
|
-
public fetch = (req: Request): Promise<Response> | Response => {
|
|
44
|
-
if (!this.compiledFetch) this.compile();
|
|
45
|
-
return this.compiledFetch!(req);
|
|
46
|
-
};
|
|
47
|
-
|
|
64
|
+
|
|
48
65
|
private compile() {
|
|
49
|
-
this.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
this.staticMap.clear();
|
|
67
|
+
this.dynamicRoutes.length = 0;
|
|
68
|
+
|
|
69
|
+
const gLen = this.globalMiddlewares.length;
|
|
70
|
+
const hasGlobal = gLen > 0;
|
|
71
|
+
const rLen = this.routes.length;
|
|
72
|
+
|
|
73
|
+
for (let i = 0; i < rLen; i++) {
|
|
74
|
+
const route = this.routes[i]!;
|
|
75
|
+
const handlers = route.handlers;
|
|
76
|
+
const hLen = handlers.length;
|
|
77
|
+
const hasDynamic = route.path.indexOf(':') !== -1;
|
|
78
|
+
|
|
79
|
+
// ULTRA FAST PATH: No middleware, single handler, no params
|
|
80
|
+
if (!hasGlobal && hLen === 1 && !hasDynamic) {
|
|
81
|
+
const h = handlers[0]!;
|
|
82
|
+
this.staticMap.set(route.method + route.path, (ctx: BareContext) => {
|
|
83
|
+
const r = h(ctx, () => ctx._finalize());
|
|
84
|
+
return r instanceof Response ? r : ctx._finalize();
|
|
85
|
+
});
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// FAST PATH: Single handler with params OR multiple handlers
|
|
90
|
+
const total = gLen + hLen;
|
|
91
|
+
let composed: Function;
|
|
72
92
|
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
if (total === 1) {
|
|
94
|
+
const h = handlers[0] || this.globalMiddlewares[0];
|
|
95
|
+
composed = (ctx: BareContext) => {
|
|
96
|
+
const r = h!(ctx, () => ctx._finalize());
|
|
97
|
+
return r instanceof Response ? r : ctx._finalize();
|
|
98
|
+
};
|
|
99
|
+
} else {
|
|
100
|
+
const pipeline = Array(total);
|
|
101
|
+
for (let j = 0; j < gLen; j++) pipeline[j] = this.globalMiddlewares[j];
|
|
102
|
+
for (let j = 0; j < hLen; j++) pipeline[gLen + j] = handlers[j];
|
|
78
103
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
104
|
+
composed = (ctx: BareContext) => {
|
|
105
|
+
let idx = 0;
|
|
106
|
+
const exec = (): any => {
|
|
107
|
+
if (idx >= total) return ctx._finalize();
|
|
108
|
+
const fn = pipeline[idx++]!;
|
|
109
|
+
const r = fn(ctx, exec);
|
|
110
|
+
if (r instanceof Response) ctx.res = r;
|
|
111
|
+
return ctx.res || (idx >= total ? ctx._finalize() : exec());
|
|
85
112
|
};
|
|
86
|
-
return
|
|
113
|
+
return exec();
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (hasDynamic) {
|
|
118
|
+
const pNames: string[] = [];
|
|
119
|
+
const regexPath = route.path.replace(/:([^/]+)/g, (_, n) => {
|
|
120
|
+
pNames.push(n);
|
|
121
|
+
return "([^/]+)";
|
|
122
|
+
});
|
|
123
|
+
this.dynamicRoutes.push({
|
|
124
|
+
m: route.method,
|
|
125
|
+
r: new RegExp(`^${regexPath}$`),
|
|
126
|
+
p: pNames,
|
|
127
|
+
c: composed
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
this.staticMap.set(route.method + route.path, composed);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// MAXIMUM JIT: Inline everything, minimal allocations
|
|
135
|
+
const sMap = this.staticMap;
|
|
136
|
+
const dRoutes = this.dynamicRoutes;
|
|
137
|
+
const dLen = dRoutes.length;
|
|
138
|
+
|
|
139
|
+
this.compiledFetch = (req: Request) => {
|
|
140
|
+
const url = req.url;
|
|
141
|
+
let i = url.indexOf('/', 8);
|
|
142
|
+
if (i === -1) i = url.length;
|
|
143
|
+
|
|
144
|
+
const path = i === url.length ? '/' : url.substring(i);
|
|
145
|
+
const key = req.method + path;
|
|
146
|
+
|
|
147
|
+
const runner = sMap.get(key);
|
|
148
|
+
if (runner) {
|
|
149
|
+
const ctx = new BareContext(req);
|
|
150
|
+
return runner(ctx);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const method = req.method;
|
|
154
|
+
for (let j = 0; j < dLen; j++) {
|
|
155
|
+
const d = dRoutes[j]!;
|
|
156
|
+
if (d.m === method) {
|
|
157
|
+
const m = d.r.exec(path);
|
|
158
|
+
if (m) {
|
|
159
|
+
const ctx = new BareContext(req);
|
|
160
|
+
const pLen = d.p.length;
|
|
161
|
+
for (let k = 0; k < pLen; k++) {
|
|
162
|
+
ctx.params[d.p[k]!] = m[k + 1]!;
|
|
163
|
+
}
|
|
164
|
+
return d.c(ctx);
|
|
165
|
+
}
|
|
87
166
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return new Response('404', { status: 404 });
|
|
170
|
+
};
|
|
92
171
|
}
|
|
93
|
-
|
|
94
|
-
public
|
|
172
|
+
|
|
173
|
+
public fetch = (req: Request) => {
|
|
174
|
+
if (!this.compiledFetch) this.compile();
|
|
175
|
+
return this.compiledFetch!(req);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
public listen(ip = '0.0.0.0', port = 3000) {
|
|
95
179
|
this.compile();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const reset = "\x1b[0m";
|
|
101
|
-
const cyan = "\x1b[36m";
|
|
102
|
-
const yellow = "\x1b[33m";
|
|
103
|
-
const gray = "\x1b[90m";
|
|
104
|
-
const bold = "\x1b[1m";
|
|
105
|
-
if (process.env.NODE_ENV !== 'production' && process.env.BARE_SILENT !== 'true') {
|
|
106
|
-
console.log(`
|
|
107
|
-
${cyan}${bold} ____ _ ____
|
|
108
|
-
| __ ) __ _ _ __ ___ | / ___|
|
|
109
|
-
| _ \\ / _\` | '__/ _ \\ _ | \\___ \\
|
|
110
|
-
| |_) | (_| | | | __/| |_| |___) |
|
|
111
|
-
|____/ \\__,_|_| \\___| \\___/|____/
|
|
112
|
-
${reset}
|
|
113
|
-
${yellow}BareJS${reset} ${gray}${reset}
|
|
114
|
-
${gray}-----------------------------------${reset}
|
|
115
|
-
🚀 Running at: ${cyan}http://${ip}:${port}${reset}
|
|
116
|
-
${gray}Ready to build everything awesome!${reset}
|
|
117
|
-
`);
|
|
118
|
-
} else {
|
|
119
|
-
|
|
120
|
-
console.log(`🚀 BareJS running at http://${ip}:${port}`);
|
|
121
|
-
}
|
|
180
|
+
console.log(`\x1b[32m⚡ BareJS MAX at http://${ip}:${port}\x1b[0m`);
|
|
181
|
+
|
|
122
182
|
return Bun.serve({
|
|
123
183
|
hostname: ip,
|
|
124
184
|
port,
|
|
125
|
-
|
|
185
|
+
reusePort: true,
|
|
186
|
+
fetch: this.fetch.bind(this),
|
|
187
|
+
websocket: {
|
|
188
|
+
open: (ws) => this.wsHandler?.handlers.open?.(ws),
|
|
189
|
+
message: (ws, msg) => this.wsHandler?.handlers.message?.(ws, msg),
|
|
190
|
+
close: (ws, code, res) => this.wsHandler?.handlers.close?.(ws, code, res),
|
|
191
|
+
}
|
|
126
192
|
});
|
|
127
193
|
}
|
|
128
|
-
}
|
|
194
|
+
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
// src/context.ts
|
|
3
|
+
export interface WSHandlers {
|
|
4
|
+
open?: (ws: any) => void;
|
|
5
|
+
message?: (ws: any, message: string | Buffer) => void;
|
|
6
|
+
close?: (ws: any, code: number, reason: string) => void;
|
|
7
|
+
drain?: (ws: any) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type Next = () => any;
|
|
11
|
+
export type Middleware = (ctx: Context, next: Next) => any;
|
|
12
|
+
export type Handler = (ctx: Context, next: Next) => any;
|
|
13
|
+
|
|
14
|
+
export interface Context {
|
|
15
|
+
req: Request;
|
|
16
|
+
res?: Response;
|
|
17
|
+
params: Record<string, string>;
|
|
18
|
+
body?: any;
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
json: (data: any) => void;
|
|
21
|
+
status: (code: number) => this;
|
|
22
|
+
setResHeader: (key: string, value: string) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class BareContext {
|
|
26
|
+
public res?: Response;
|
|
27
|
+
public params: Record<string, string> = {};
|
|
28
|
+
public body: any;
|
|
29
|
+
public _status = 200;
|
|
30
|
+
public _headers: Record<string, string> = {};
|
|
31
|
+
|
|
32
|
+
constructor(public req: Request) {}
|
|
33
|
+
|
|
34
|
+
json(data: any) {
|
|
35
|
+
this._headers["Content-Type"] = "application/json";
|
|
36
|
+
this.res = new Response(JSON.stringify(data), {
|
|
37
|
+
status: this._status,
|
|
38
|
+
headers: this._headers,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
status(code: number) {
|
|
43
|
+
this._status = code;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setResHeader(k: string, v: string) {
|
|
48
|
+
this._headers[k] = v;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_finalize() {
|
|
52
|
+
return this.res || new Response(null, { status: this._status, headers: this._headers });
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { BareJS
|
|
2
|
-
import {
|
|
1
|
+
import { BareJS} from './bare';
|
|
2
|
+
import type { Context } from './context';
|
|
3
|
+
import { typebox, native } from './validators';
|
|
3
4
|
import * as TB from '@sinclair/typebox';
|
|
4
5
|
|
|
5
6
|
const app = new BareJS();
|
|
@@ -15,6 +16,7 @@ app.post('/users-tb', typebox(UserSchema), (ctx: Context) => {
|
|
|
15
16
|
return ctx.json({ message: "Saved via TypeBox", user: ctx.body });
|
|
16
17
|
});
|
|
17
18
|
|
|
19
|
+
|
|
18
20
|
// ✅ Route 2: Using Native Validator (Safe alternative if TypeBox has issues)
|
|
19
21
|
app.post('/users-native', native(UserSchema), (ctx: Context) => {
|
|
20
22
|
return ctx.json({ message: "Saved via Native", user: ctx.body });
|
|
@@ -22,5 +24,16 @@ app.post('/users-native', native(UserSchema), (ctx: Context) => {
|
|
|
22
24
|
|
|
23
25
|
// ✅ Route 3: No Validator (Pure speed, 0 ns overhead)
|
|
24
26
|
app.get('/ping', (ctx: Context) => ctx.json({ message: "pong" }));
|
|
27
|
+
// Dynamic Path
|
|
28
|
+
app.get('/user/:id', (ctx: Context) => {
|
|
29
|
+
const userId = ctx.params.id;
|
|
30
|
+
return ctx.json({ user: userId, status: 'active' });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Multiple Params
|
|
34
|
+
app.get('/post/:category/:id', (ctx: Context) => {
|
|
35
|
+
return ctx.json(ctx.params); // { category: 'tech', id: '1' }
|
|
36
|
+
});
|
|
37
|
+
|
|
25
38
|
|
|
26
39
|
app.listen('0.0.0.0', 3000);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/validators.ts
|
|
2
|
+
import * as Compiler from '@sinclair/typebox/compiler';
|
|
3
|
+
import type { Context, Next } from './context';
|
|
4
|
+
|
|
5
|
+
export const typebox = (schema: any) => {
|
|
6
|
+
const check = Compiler.TypeCompiler.Compile(schema);
|
|
7
|
+
return async (ctx: Context, next: Next) => {
|
|
8
|
+
try {
|
|
9
|
+
const body = await ctx.req.json();
|
|
10
|
+
if (!check.Check(body)) return new Response("Validation Failed", { status: 400 });
|
|
11
|
+
ctx.body = body;
|
|
12
|
+
return next();
|
|
13
|
+
} catch {
|
|
14
|
+
return new Response("Invalid JSON", { status: 400 });
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const native = (schema: any) => {
|
|
20
|
+
const props = schema.properties || {};
|
|
21
|
+
const keys = Object.keys(props);
|
|
22
|
+
const kLen = keys.length;
|
|
23
|
+
|
|
24
|
+
return async (ctx: Context, next: Next) => {
|
|
25
|
+
try {
|
|
26
|
+
const body = await ctx.req.json() as any;
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < kLen; i++) {
|
|
29
|
+
const k = keys[i]!;
|
|
30
|
+
if (typeof body[k] !== props[k]?.type) {
|
|
31
|
+
return new Response(`Validation Failed: ${k}`, { status: 400 });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
ctx.body = body;
|
|
36
|
+
return next();
|
|
37
|
+
} catch {
|
|
38
|
+
return new Response("Invalid JSON", { status: 400 });
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const zod = (schema: any) => {
|
|
44
|
+
return async (ctx: Context, next: Next) => {
|
|
45
|
+
try {
|
|
46
|
+
const body = await ctx.req.json();
|
|
47
|
+
const result = schema.safeParse(body);
|
|
48
|
+
if (!result.success) return new Response(JSON.stringify(result.error), { status: 400 });
|
|
49
|
+
ctx.body = result.data;
|
|
50
|
+
return next();
|
|
51
|
+
} catch {
|
|
52
|
+
return new Response("Invalid JSON", { status: 400 });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import * as Compiler from '@sinclair/typebox/compiler';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 1. TypeBox Validator: Highest Performance (JIT Optimized)
|
|
5
|
-
* Best for: Production and Benchmarking
|
|
6
|
-
*/
|
|
7
|
-
export const typebox = (schema: any) => {
|
|
8
|
-
const check = Compiler.TypeCompiler.Compile(schema);
|
|
9
|
-
return async (ctx: any, next: any) => {
|
|
10
|
-
try {
|
|
11
|
-
const body = await ctx.req.json();
|
|
12
|
-
if (!check.Check(body)) return new Response("TypeBox Validation Failed", { status: 400 });
|
|
13
|
-
ctx.body = body;
|
|
14
|
-
return next();
|
|
15
|
-
} catch { return new Response("Invalid JSON", { status: 400 }); }
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 2. Native Validator: Zero Dependency
|
|
21
|
-
* Best for: Avoiding Runtime bugs or keeping the bundle lightweight.
|
|
22
|
-
*/
|
|
23
|
-
export const native = (schema: any) => {
|
|
24
|
-
const properties = schema.properties || {};
|
|
25
|
-
const keys = Object.keys(properties);
|
|
26
|
-
return async (ctx: any, next: any) => {
|
|
27
|
-
try {
|
|
28
|
-
const body = await ctx.req.json();
|
|
29
|
-
for (const key of keys) {
|
|
30
|
-
if (typeof body[key] !== properties[key].type)
|
|
31
|
-
return new Response(`Native Validation Failed: ${key} is not ${properties[key].type}`, { status: 400 });
|
|
32
|
-
}
|
|
33
|
-
ctx.body = body;
|
|
34
|
-
return next();
|
|
35
|
-
} catch { return new Response("Invalid JSON", { status: 400 }); }
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 3. Zod Validator: Best Developer Experience
|
|
41
|
-
* Note: Requires 'npm install zod'
|
|
42
|
-
*/
|
|
43
|
-
export const zod = (schema: any) => {
|
|
44
|
-
return async (ctx: any, next: any) => {
|
|
45
|
-
try {
|
|
46
|
-
const body = await ctx.req.json();
|
|
47
|
-
const result = schema.safeParse(body);
|
|
48
|
-
if (!result.success) return new Response(JSON.stringify(result.error), { status: 400 });
|
|
49
|
-
ctx.body = result.data;
|
|
50
|
-
return next();
|
|
51
|
-
} catch { return new Response("Invalid JSON", { status: 400 }); }
|
|
52
|
-
};
|
|
53
|
-
};
|
package/src/types.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// src/context.ts
|
|
2
|
-
export class Context {
|
|
3
|
-
public res: Response;
|
|
4
|
-
|
|
5
|
-
constructor(public req: Request) {
|
|
6
|
-
this.res = new Response("Not Found", { status: 404 });
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
json(data: any) {
|
|
10
|
-
this.res = new Response(JSON.stringify(data), {
|
|
11
|
-
headers: { "Content-Type": "application/json" },
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
setResHeader(key: string, value: string) {
|
|
17
|
-
const newHeaders = new Headers(this.res.headers);
|
|
18
|
-
newHeaders.set(key, value);
|
|
19
|
-
this.res = new Response(this.res.body, {
|
|
20
|
-
status: this.res.status,
|
|
21
|
-
headers: newHeaders,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|