princejs 1.3.6 → 1.4.1
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 +54 -57
- package/dist/index.js +346 -0
- package/package.json +22 -6
package/Readme.md
CHANGED
|
@@ -1,93 +1,90 @@
|
|
|
1
|
-
#
|
|
1
|
+
# princejs — The Smallest Bun Framework in History
|
|
2
2
|
|
|
3
|
-
**
|
|
4
|
-
|
|
3
|
+
**2.8 kB gzipped** • **~600k req/30s** • **Built by a 13yo Nigerian**
|
|
4
|
+
|
|
5
|
+
> *"I didn’t beat Elysia. I outsmarted it."* — @Lil_Prince_1218
|
|
5
6
|
|
|
6
7
|
---
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
## 🚀 Get Started
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
bun
|
|
14
|
-
# or
|
|
15
|
-
npm install princejs
|
|
12
|
+
bun create princejs my-app
|
|
13
|
+
cd my-app
|
|
14
|
+
bun dev
|
|
16
15
|
```
|
|
17
16
|
|
|
18
|
-
### Quick Start
|
|
19
|
-
|
|
20
17
|
```ts
|
|
21
|
-
import { Prince } from
|
|
18
|
+
import { Prince } from "princejs";
|
|
19
|
+
import { cors } from "princejs/middleware";
|
|
22
20
|
|
|
23
|
-
const app = new Prince()
|
|
21
|
+
const app = new Prince()
|
|
22
|
+
.use(cors())
|
|
23
|
+
.get("/", () => "Hello princejs")
|
|
24
|
+
.get("/users/:id", (req) => ({ id: req.params.id }));
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
console.log(`${req.method} ${req.url}`);
|
|
28
|
-
const res = await next();
|
|
29
|
-
res.headers.set('Access-Control-Allow-Origin', '*');
|
|
30
|
-
return res;
|
|
31
|
-
});
|
|
26
|
+
app.listen(5000);
|
|
27
|
+
```
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
app.error((err) => app.json({ error: err.message }, 500));
|
|
29
|
+
---
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
app.get('/', () => app.json({ hello: 'PrinceJS', age: 13 }));
|
|
31
|
+
## ⚔️ Size War (Gzipped — Real World)
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
| Framework | Gzipped | Minified | vs princejs |
|
|
34
|
+
| ------------ | ---------- | ---------- | ----------- |
|
|
35
|
+
| **princejs** | **2.8 kB** | **7.8 kB** | — |
|
|
36
|
+
| **Hono** | 7.3 kB | 18.7 kB | 2.6× bigger |
|
|
37
|
+
| **Elysia** | 62.5 kB | 245 kB | 22× bigger |
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
```
|
|
39
|
+
> princejs fits in a tweet. Elysia needs a ZIP file.
|
|
47
40
|
|
|
48
41
|
---
|
|
49
42
|
|
|
50
|
-
##
|
|
43
|
+
## ⚡ Benchmarks (3×3 — Windows, Nov 11, 2025)
|
|
51
44
|
|
|
52
|
-
|
|
45
|
+
| Framework | Requests (30s) | Req/s | Notes |
|
|
46
|
+
| ------------ | -------------- | ---------- | -------------- |
|
|
47
|
+
| **princejs** | **599k** | **19,966** | 🥈 2nd fastest |
|
|
48
|
+
| **Elysia** | 602k | 20,071 | 🥇 0.5% faster |
|
|
49
|
+
| **Hono** | 578k | 19,254 | 🥉 Slower |
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
app.json(data, status?) — clean JSON with status
|
|
56
|
-
app.error(handler) — global error handling
|
|
57
|
-
```
|
|
51
|
+
> Elysia is only 0.5% faster. But princejs is **22× smaller**.
|
|
58
52
|
|
|
59
53
|
---
|
|
60
54
|
|
|
61
|
-
##
|
|
62
|
-
|
|
63
|
-
Real-world 30-second load test with `autocannon -c 100 -d 30`.
|
|
55
|
+
## 🧹 Features
|
|
64
56
|
|
|
65
|
-
|
|
57
|
+
```ts
|
|
58
|
+
.use(rateLimit({ max: 100 }))
|
|
59
|
+
.use(validate(z.object({ name: z.string() })))
|
|
60
|
+
```
|
|
66
61
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| Hono | 8,044.8 | 241,000 | 1.08 MB/s | 11.22 ms |
|
|
71
|
-
| Elysia | 9,531.21 | 286,000 | 1.28 MB/s | 10 ms |
|
|
62
|
+
✅ Zod Validation
|
|
63
|
+
✅ CORS + Logger
|
|
64
|
+
✅ Rate Limit Middleware
|
|
72
65
|
|
|
73
66
|
---
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Matthew Micheal — Nigeria
|
|
68
|
+
## 📦 Install
|
|
78
69
|
|
|
79
|
-
|
|
70
|
+
```bash
|
|
71
|
+
npm i princejs
|
|
72
|
+
# or
|
|
73
|
+
bun add princejs
|
|
74
|
+
```
|
|
80
75
|
|
|
81
|
-
|
|
76
|
+
---
|
|
82
77
|
|
|
83
|
-
|
|
78
|
+
## 📚 Docs
|
|
84
79
|
|
|
85
|
-
|
|
80
|
+
**coming soon →** [princejs.vercel.app](https://princejs.vercel.app)
|
|
86
81
|
|
|
87
82
|
---
|
|
88
83
|
|
|
89
|
-
|
|
84
|
+
## 🇳🇬 Built in Nigeria
|
|
90
85
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
**@Lil_Prince_1218 — 13 years old**
|
|
87
|
+
Lagos, Nigeria
|
|
88
|
+
**November 11, 2025**
|
|
89
|
+
|
|
90
|
+
> *“2.8 kB. 600k req. No excuses.”*
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/prince.ts
|
|
3
|
+
class TrieNode {
|
|
4
|
+
children = Object.create(null);
|
|
5
|
+
paramChild;
|
|
6
|
+
wildcardChild;
|
|
7
|
+
catchAllChild;
|
|
8
|
+
handlers = null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class ResponseBuilder {
|
|
12
|
+
_status = 200;
|
|
13
|
+
_headers = {};
|
|
14
|
+
_body = null;
|
|
15
|
+
status(code) {
|
|
16
|
+
this._status = code;
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
header(key, value) {
|
|
20
|
+
this._headers[key] = value;
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
json(data) {
|
|
24
|
+
this._headers["Content-Type"] = "application/json";
|
|
25
|
+
this._body = JSON.stringify(data);
|
|
26
|
+
return this.build();
|
|
27
|
+
}
|
|
28
|
+
text(data) {
|
|
29
|
+
this._headers["Content-Type"] = "text/plain";
|
|
30
|
+
this._body = data;
|
|
31
|
+
return this.build();
|
|
32
|
+
}
|
|
33
|
+
html(data) {
|
|
34
|
+
this._headers["Content-Type"] = "text/html";
|
|
35
|
+
this._body = data;
|
|
36
|
+
return this.build();
|
|
37
|
+
}
|
|
38
|
+
redirect(url, status = 302) {
|
|
39
|
+
this._status = status;
|
|
40
|
+
this._headers["Location"] = url;
|
|
41
|
+
return this.build();
|
|
42
|
+
}
|
|
43
|
+
build() {
|
|
44
|
+
return new Response(this._body, {
|
|
45
|
+
status: this._status,
|
|
46
|
+
headers: this._headers
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class Prince {
|
|
52
|
+
devMode;
|
|
53
|
+
rawRoutes = [];
|
|
54
|
+
middlewares = [];
|
|
55
|
+
errorHandler;
|
|
56
|
+
prefix = "";
|
|
57
|
+
constructor(devMode = false) {
|
|
58
|
+
this.devMode = devMode;
|
|
59
|
+
}
|
|
60
|
+
use(mw) {
|
|
61
|
+
this.middlewares.push(mw);
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
error(fn) {
|
|
65
|
+
this.errorHandler = fn;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
json(data, status = 200) {
|
|
69
|
+
return new Response(JSON.stringify(data), {
|
|
70
|
+
status,
|
|
71
|
+
headers: { "Content-Type": "application/json" }
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
response() {
|
|
75
|
+
return new ResponseBuilder;
|
|
76
|
+
}
|
|
77
|
+
route(path) {
|
|
78
|
+
const group = new Prince(this.devMode);
|
|
79
|
+
group.prefix = path;
|
|
80
|
+
group.middlewares = [...this.middlewares];
|
|
81
|
+
return {
|
|
82
|
+
get: (subpath, handler) => {
|
|
83
|
+
this.get(path + subpath, handler);
|
|
84
|
+
return group;
|
|
85
|
+
},
|
|
86
|
+
post: (subpath, handler) => {
|
|
87
|
+
this.post(path + subpath, handler);
|
|
88
|
+
return group;
|
|
89
|
+
},
|
|
90
|
+
put: (subpath, handler) => {
|
|
91
|
+
this.put(path + subpath, handler);
|
|
92
|
+
return group;
|
|
93
|
+
},
|
|
94
|
+
delete: (subpath, handler) => {
|
|
95
|
+
this.delete(path + subpath, handler);
|
|
96
|
+
return group;
|
|
97
|
+
},
|
|
98
|
+
patch: (subpath, handler) => {
|
|
99
|
+
this.patch(path + subpath, handler);
|
|
100
|
+
return group;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
get(path, handler) {
|
|
105
|
+
return this.add("GET", path, handler);
|
|
106
|
+
}
|
|
107
|
+
post(path, handler) {
|
|
108
|
+
return this.add("POST", path, handler);
|
|
109
|
+
}
|
|
110
|
+
put(path, handler) {
|
|
111
|
+
return this.add("PUT", path, handler);
|
|
112
|
+
}
|
|
113
|
+
delete(path, handler) {
|
|
114
|
+
return this.add("DELETE", path, handler);
|
|
115
|
+
}
|
|
116
|
+
patch(path, handler) {
|
|
117
|
+
return this.add("PATCH", path, handler);
|
|
118
|
+
}
|
|
119
|
+
options(path, handler) {
|
|
120
|
+
return this.add("OPTIONS", path, handler);
|
|
121
|
+
}
|
|
122
|
+
head(path, handler) {
|
|
123
|
+
return this.add("HEAD", path, handler);
|
|
124
|
+
}
|
|
125
|
+
add(method, path, handler) {
|
|
126
|
+
if (!path.startsWith("/"))
|
|
127
|
+
path = "/" + path;
|
|
128
|
+
if (path.length > 1 && path.endsWith("/"))
|
|
129
|
+
path = path.slice(0, -1);
|
|
130
|
+
const parts = path === "/" ? [""] : path.split("/").slice(1);
|
|
131
|
+
this.rawRoutes.push({ method: method.toUpperCase(), path, parts, handler });
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
parseUrl(req) {
|
|
135
|
+
const url = new URL(req.url);
|
|
136
|
+
const query = {};
|
|
137
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
138
|
+
query[key] = value;
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
pathname: url.pathname,
|
|
142
|
+
query
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async parseBody(req) {
|
|
146
|
+
const ct = req.headers.get("content-type") || "";
|
|
147
|
+
if (ct.includes("application/json")) {
|
|
148
|
+
return await req.json();
|
|
149
|
+
}
|
|
150
|
+
if (ct.includes("application/x-www-form-urlencoded")) {
|
|
151
|
+
const text = await req.text();
|
|
152
|
+
const params = {};
|
|
153
|
+
const pairs = text.split("&");
|
|
154
|
+
for (const pair of pairs) {
|
|
155
|
+
const [key, val] = pair.split("=");
|
|
156
|
+
params[decodeURIComponent(key)] = decodeURIComponent(val || "");
|
|
157
|
+
}
|
|
158
|
+
return params;
|
|
159
|
+
}
|
|
160
|
+
if (ct.includes("text/")) {
|
|
161
|
+
return await req.text();
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
buildRouter() {
|
|
166
|
+
const root = new TrieNode;
|
|
167
|
+
for (const route of this.rawRoutes) {
|
|
168
|
+
let node = root;
|
|
169
|
+
const parts = route.parts;
|
|
170
|
+
if (parts.length === 1 && parts[0] === "") {
|
|
171
|
+
if (!node.handlers)
|
|
172
|
+
node.handlers = Object.create(null);
|
|
173
|
+
node.handlers[route.method] = route.handler;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
for (let i = 0;i < parts.length; i++) {
|
|
177
|
+
const part = parts[i];
|
|
178
|
+
if (part === "**") {
|
|
179
|
+
if (!node.catchAllChild) {
|
|
180
|
+
node.catchAllChild = { name: "**", node: new TrieNode };
|
|
181
|
+
}
|
|
182
|
+
node = node.catchAllChild.node;
|
|
183
|
+
break;
|
|
184
|
+
} else if (part === "*") {
|
|
185
|
+
if (!node.wildcardChild)
|
|
186
|
+
node.wildcardChild = new TrieNode;
|
|
187
|
+
node = node.wildcardChild;
|
|
188
|
+
} else if (part.startsWith(":")) {
|
|
189
|
+
const name = part.slice(1);
|
|
190
|
+
if (!node.paramChild)
|
|
191
|
+
node.paramChild = { name, node: new TrieNode };
|
|
192
|
+
node = node.paramChild.node;
|
|
193
|
+
} else {
|
|
194
|
+
if (!node.children[part])
|
|
195
|
+
node.children[part] = new TrieNode;
|
|
196
|
+
node = node.children[part];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!node.handlers)
|
|
200
|
+
node.handlers = Object.create(null);
|
|
201
|
+
node.handlers[route.method] = route.handler;
|
|
202
|
+
}
|
|
203
|
+
return root;
|
|
204
|
+
}
|
|
205
|
+
compilePipeline(handler, paramsGetter) {
|
|
206
|
+
const mws = this.middlewares.slice();
|
|
207
|
+
const hasMiddleware = mws.length > 0;
|
|
208
|
+
if (!hasMiddleware) {
|
|
209
|
+
return async (req, params, query) => {
|
|
210
|
+
const princeReq = req;
|
|
211
|
+
princeReq.params = params;
|
|
212
|
+
princeReq.query = query;
|
|
213
|
+
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") {
|
|
214
|
+
princeReq.body = await this.parseBody(req);
|
|
215
|
+
}
|
|
216
|
+
const res = await handler(princeReq);
|
|
217
|
+
if (res instanceof Response)
|
|
218
|
+
return res;
|
|
219
|
+
if (typeof res === "string")
|
|
220
|
+
return new Response(res, { status: 200 });
|
|
221
|
+
if (res instanceof Uint8Array || res instanceof ArrayBuffer)
|
|
222
|
+
return new Response(res, { status: 200 });
|
|
223
|
+
return this.json(res);
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return async (req, params, query) => {
|
|
227
|
+
const princeReq = req;
|
|
228
|
+
princeReq.params = params;
|
|
229
|
+
princeReq.query = query;
|
|
230
|
+
let idx = 0;
|
|
231
|
+
const runNext = async () => {
|
|
232
|
+
if (idx >= mws.length) {
|
|
233
|
+
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") {
|
|
234
|
+
princeReq.body = await this.parseBody(req);
|
|
235
|
+
}
|
|
236
|
+
const res = await handler(princeReq);
|
|
237
|
+
if (res instanceof Response)
|
|
238
|
+
return res;
|
|
239
|
+
if (typeof res === "string")
|
|
240
|
+
return new Response(res, { status: 200 });
|
|
241
|
+
if (res instanceof Uint8Array || res instanceof ArrayBuffer)
|
|
242
|
+
return new Response(res, { status: 200 });
|
|
243
|
+
return this.json(res);
|
|
244
|
+
}
|
|
245
|
+
const mw = mws[idx++];
|
|
246
|
+
return await mw(req, runNext);
|
|
247
|
+
};
|
|
248
|
+
const out = await runNext();
|
|
249
|
+
if (out instanceof Response)
|
|
250
|
+
return out;
|
|
251
|
+
if (out !== undefined) {
|
|
252
|
+
if (typeof out === "string")
|
|
253
|
+
return new Response(out, { status: 200 });
|
|
254
|
+
if (out instanceof Uint8Array || out instanceof ArrayBuffer)
|
|
255
|
+
return new Response(out, { status: 200 });
|
|
256
|
+
return this.json(out);
|
|
257
|
+
}
|
|
258
|
+
return new Response(null, { status: 204 });
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
listen(port = 3000) {
|
|
262
|
+
const root = this.buildRouter();
|
|
263
|
+
const handlerMap = new Map;
|
|
264
|
+
Bun.serve({
|
|
265
|
+
port,
|
|
266
|
+
fetch: async (req) => {
|
|
267
|
+
try {
|
|
268
|
+
const { pathname, query } = this.parseUrl(req);
|
|
269
|
+
const segments = pathname === "/" ? [] : pathname.slice(1).split("/");
|
|
270
|
+
let node = root;
|
|
271
|
+
const params = {};
|
|
272
|
+
let matched = true;
|
|
273
|
+
if (segments.length === 0) {
|
|
274
|
+
if (!node.handlers)
|
|
275
|
+
return this.json({ error: "Route not found" }, 404);
|
|
276
|
+
const handler2 = node.handlers[req.method];
|
|
277
|
+
if (!handler2)
|
|
278
|
+
return this.json({ error: "Method not allowed" }, 405);
|
|
279
|
+
let methodMap2 = handlerMap.get(node);
|
|
280
|
+
if (!methodMap2) {
|
|
281
|
+
methodMap2 = {};
|
|
282
|
+
handlerMap.set(node, methodMap2);
|
|
283
|
+
}
|
|
284
|
+
if (!methodMap2[req.method]) {
|
|
285
|
+
methodMap2[req.method] = this.compilePipeline(handler2, (_) => params);
|
|
286
|
+
}
|
|
287
|
+
return await methodMap2[req.method](req, params, query);
|
|
288
|
+
}
|
|
289
|
+
for (let i = 0;i < segments.length; i++) {
|
|
290
|
+
const seg = segments[i];
|
|
291
|
+
if (node.children[seg]) {
|
|
292
|
+
node = node.children[seg];
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (node.paramChild) {
|
|
296
|
+
params[node.paramChild.name] = seg;
|
|
297
|
+
node = node.paramChild.node;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (node.wildcardChild) {
|
|
301
|
+
node = node.wildcardChild;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (node.catchAllChild) {
|
|
305
|
+
const remaining = segments.slice(i).join("/");
|
|
306
|
+
if (node.catchAllChild.name)
|
|
307
|
+
params[node.catchAllChild.name] = remaining;
|
|
308
|
+
node = node.catchAllChild.node;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
matched = false;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
if (!matched || !node || !node.handlers) {
|
|
315
|
+
return this.json({ error: "Route not found" }, 404);
|
|
316
|
+
}
|
|
317
|
+
const handler = node.handlers[req.method];
|
|
318
|
+
if (!handler)
|
|
319
|
+
return this.json({ error: "Method not allowed" }, 405);
|
|
320
|
+
let methodMap = handlerMap.get(node);
|
|
321
|
+
if (!methodMap) {
|
|
322
|
+
methodMap = {};
|
|
323
|
+
handlerMap.set(node, methodMap);
|
|
324
|
+
}
|
|
325
|
+
if (!methodMap[req.method]) {
|
|
326
|
+
methodMap[req.method] = this.compilePipeline(handler, (_) => params);
|
|
327
|
+
}
|
|
328
|
+
return await methodMap[req.method](req, params, query);
|
|
329
|
+
} catch (err) {
|
|
330
|
+
if (this.errorHandler) {
|
|
331
|
+
try {
|
|
332
|
+
return this.errorHandler(err, req);
|
|
333
|
+
} catch {}
|
|
334
|
+
}
|
|
335
|
+
return this.json({ error: String(err) }, 500);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
console.log(`\uD83D\uDE80 PrinceJS running at http://localhost:${port}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
var prince = (dev = false) => new Prince(dev);
|
|
343
|
+
export {
|
|
344
|
+
prince,
|
|
345
|
+
Prince
|
|
346
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "princejs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "An easy and fast backend framework — by a 13yo developer, for developers.",
|
|
5
5
|
"main": "dist/prince.js",
|
|
6
6
|
"types": "dist/prince.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/prince.js",
|
|
10
|
+
"types": "./dist/prince.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./middleware": {
|
|
13
|
+
"import": "./dist/middleware.js",
|
|
14
|
+
"types": "./dist/middleware.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./validation": {
|
|
17
|
+
"import": "./dist/validation.js",
|
|
18
|
+
"types": "./dist/validation.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
7
21
|
"files": [
|
|
8
22
|
"dist"
|
|
9
23
|
],
|
|
@@ -13,7 +27,10 @@
|
|
|
13
27
|
"framework",
|
|
14
28
|
"bun",
|
|
15
29
|
"easy",
|
|
16
|
-
"princejs"
|
|
30
|
+
"princejs",
|
|
31
|
+
"rest",
|
|
32
|
+
"server",
|
|
33
|
+
"typescript"
|
|
17
34
|
],
|
|
18
35
|
"author": "Matthew Michael (MatthewTheCoder1218)",
|
|
19
36
|
"license": "MIT",
|
|
@@ -23,12 +40,11 @@
|
|
|
23
40
|
},
|
|
24
41
|
"devDependencies": {
|
|
25
42
|
"@types/bun": "^1.3.2",
|
|
26
|
-
"bun-types": "latest"
|
|
27
|
-
|
|
28
|
-
"dependencies": {
|
|
43
|
+
"bun-types": "latest",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
29
45
|
"zod": "^4.1.12"
|
|
30
46
|
},
|
|
31
47
|
"scripts": {
|
|
32
|
-
"build": "bun build
|
|
48
|
+
"build": "bun build src/index.ts --outdir dist --target bun && bun build src/middleware.ts --outdir dist --target bun && bun build src/validation.ts --outdir dist --target bun"
|
|
33
49
|
}
|
|
34
50
|
}
|