princejs 1.2.3 → 1.3.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/LICENSE +21 -0
- package/Readme.md +1 -1
- package/dist/prince.js +179 -34
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Matthew Michael (MatthewTheCoder1218)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Readme.md
CHANGED
package/dist/prince.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// prince.ts
|
|
3
|
+
class TrieNode {
|
|
4
|
+
children = Object.create(null);
|
|
5
|
+
paramChild;
|
|
6
|
+
wildcardChild;
|
|
7
|
+
catchAllChild;
|
|
8
|
+
handlers = null;
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
class Prince {
|
|
4
|
-
|
|
12
|
+
devMode;
|
|
13
|
+
rawRoutes = [];
|
|
5
14
|
middlewares = [];
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
errorHandler;
|
|
16
|
+
constructor(devMode = false) {
|
|
17
|
+
this.devMode = devMode;
|
|
18
|
+
}
|
|
19
|
+
use(mw) {
|
|
20
|
+
this.middlewares.push(mw);
|
|
8
21
|
return this;
|
|
9
22
|
}
|
|
10
|
-
error(
|
|
11
|
-
this.
|
|
12
|
-
try {
|
|
13
|
-
return await next();
|
|
14
|
-
} catch (err) {
|
|
15
|
-
return handler(err, req);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
23
|
+
error(fn) {
|
|
24
|
+
this.errorHandler = fn;
|
|
18
25
|
return this;
|
|
19
26
|
}
|
|
20
27
|
json(data, status = 200) {
|
|
@@ -45,45 +52,183 @@ class Prince {
|
|
|
45
52
|
return this.add("HEAD", path, handler);
|
|
46
53
|
}
|
|
47
54
|
add(method, path, handler) {
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
if (!path.startsWith("/"))
|
|
56
|
+
path = "/" + path;
|
|
57
|
+
if (path.length > 1 && path.endsWith("/"))
|
|
58
|
+
path = path.slice(0, -1);
|
|
59
|
+
const parts = path === "/" ? [""] : path.split("/").slice(1);
|
|
60
|
+
this.rawRoutes.push({ method: method.toUpperCase(), path, parts, handler });
|
|
50
61
|
return this;
|
|
51
62
|
}
|
|
63
|
+
fastPathname(req) {
|
|
64
|
+
const u = req.url;
|
|
65
|
+
const protoSep = u.indexOf("://");
|
|
66
|
+
const start = protoSep !== -1 ? u.indexOf("/", protoSep + 3) : u.indexOf("/");
|
|
67
|
+
if (start === -1)
|
|
68
|
+
return "/";
|
|
69
|
+
const q = u.indexOf("?", start);
|
|
70
|
+
const h = u.indexOf("#", start);
|
|
71
|
+
const end = q !== -1 ? q : h !== -1 ? h : u.length;
|
|
72
|
+
return u.slice(start, end);
|
|
73
|
+
}
|
|
74
|
+
buildRouter() {
|
|
75
|
+
const root = new TrieNode;
|
|
76
|
+
for (const route of this.rawRoutes) {
|
|
77
|
+
let node = root;
|
|
78
|
+
const parts = route.parts;
|
|
79
|
+
if (parts.length === 1 && parts[0] === "") {
|
|
80
|
+
if (!node.handlers)
|
|
81
|
+
node.handlers = Object.create(null);
|
|
82
|
+
node.handlers[route.method] = route.handler;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
for (let i = 0;i < parts.length; i++) {
|
|
86
|
+
const part = parts[i];
|
|
87
|
+
if (part === "**") {
|
|
88
|
+
node.catchAllChild ??= { node: new TrieNode };
|
|
89
|
+
node = node.catchAllChild.node;
|
|
90
|
+
break;
|
|
91
|
+
} else if (part === "*") {
|
|
92
|
+
if (!node.wildcardChild)
|
|
93
|
+
node.wildcardChild = new TrieNode;
|
|
94
|
+
node = node.wildcardChild;
|
|
95
|
+
} else if (part.startsWith(":")) {
|
|
96
|
+
const name = part.slice(1);
|
|
97
|
+
if (!node.paramChild)
|
|
98
|
+
node.paramChild = { name, node: new TrieNode };
|
|
99
|
+
node = node.paramChild.node;
|
|
100
|
+
} else {
|
|
101
|
+
if (!node.children[part])
|
|
102
|
+
node.children[part] = new TrieNode;
|
|
103
|
+
node = node.children[part];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!node.handlers)
|
|
107
|
+
node.handlers = Object.create(null);
|
|
108
|
+
node.handlers[route.method] = route.handler;
|
|
109
|
+
}
|
|
110
|
+
return root;
|
|
111
|
+
}
|
|
112
|
+
compilePipeline(handler, paramsFromMatch) {
|
|
113
|
+
const mws = this.middlewares.slice();
|
|
114
|
+
return async (req) => {
|
|
115
|
+
let idx = 0;
|
|
116
|
+
const runNext = async () => {
|
|
117
|
+
if (idx >= mws.length) {
|
|
118
|
+
const params = paramsFromMatch(req);
|
|
119
|
+
const res = await handler(req, params);
|
|
120
|
+
if (res instanceof Response)
|
|
121
|
+
return res;
|
|
122
|
+
if (typeof res === "string")
|
|
123
|
+
return new Response(res, { status: 200 });
|
|
124
|
+
if (res instanceof Uint8Array || res instanceof ArrayBuffer)
|
|
125
|
+
return new Response(res, { status: 200 });
|
|
126
|
+
return this.json(res);
|
|
127
|
+
}
|
|
128
|
+
const mw = mws[idx++];
|
|
129
|
+
const maybe = await mw(req, runNext);
|
|
130
|
+
return maybe;
|
|
131
|
+
};
|
|
132
|
+
const out = await runNext();
|
|
133
|
+
if (out instanceof Response)
|
|
134
|
+
return out;
|
|
135
|
+
if (out !== undefined) {
|
|
136
|
+
if (typeof out === "string")
|
|
137
|
+
return new Response(out, { status: 200 });
|
|
138
|
+
if (out instanceof Uint8Array || out instanceof ArrayBuffer)
|
|
139
|
+
return new Response(out, { status: 200 });
|
|
140
|
+
return this.json(out);
|
|
141
|
+
}
|
|
142
|
+
return new Response(null, { status: 204 });
|
|
143
|
+
};
|
|
144
|
+
}
|
|
52
145
|
listen(port = 3000) {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
return Bun.serve({
|
|
146
|
+
const root = this.buildRouter();
|
|
147
|
+
const handlerMap = new Map;
|
|
148
|
+
Bun.serve({
|
|
57
149
|
port,
|
|
58
150
|
fetch: async (req) => {
|
|
59
151
|
try {
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
152
|
+
const pathname = this.fastPathname(req);
|
|
153
|
+
const segments = pathname === "/" ? [] : pathname.slice(1).split("/");
|
|
154
|
+
let node = root;
|
|
155
|
+
const params = Object.create(null);
|
|
156
|
+
let matched = true;
|
|
157
|
+
if (segments.length === 0) {
|
|
158
|
+
if (!node.handlers)
|
|
159
|
+
return this.json({ error: "Route not found" }, 404);
|
|
160
|
+
const handler2 = node.handlers[req.method];
|
|
161
|
+
if (!handler2)
|
|
162
|
+
return this.json({ error: "Method not allowed" }, 405);
|
|
163
|
+
let methodMap2 = handlerMap.get(node);
|
|
164
|
+
if (!methodMap2) {
|
|
165
|
+
methodMap2 = Object.create(null);
|
|
166
|
+
handlerMap.set(node, methodMap2);
|
|
167
|
+
}
|
|
168
|
+
if (!methodMap2[req.method]) {
|
|
169
|
+
methodMap2[req.method] = this.compilePipeline(handler2, (_) => params);
|
|
170
|
+
}
|
|
171
|
+
return await methodMap2[req.method](req);
|
|
172
|
+
}
|
|
173
|
+
for (let i = 0;i < segments.length; i++) {
|
|
174
|
+
const seg = segments[i];
|
|
175
|
+
if (!node) {
|
|
176
|
+
matched = false;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
if (node.children[seg]) {
|
|
180
|
+
node = node.children[seg];
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (node.paramChild) {
|
|
184
|
+
params[node.paramChild.name] = seg;
|
|
185
|
+
node = node.paramChild.node;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (node.wildcardChild) {
|
|
189
|
+
node = node.wildcardChild;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (node.catchAllChild) {
|
|
193
|
+
const remaining = segments.slice(i).join("/");
|
|
194
|
+
if (node.catchAllChild.name)
|
|
195
|
+
params[node.catchAllChild.name] = remaining;
|
|
196
|
+
node = node.catchAllChild.node;
|
|
197
|
+
i = segments.length;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
matched = false;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
if (!matched || !node || !node.handlers)
|
|
65
204
|
return this.json({ error: "Route not found" }, 404);
|
|
205
|
+
const byMethod = node.handlers;
|
|
206
|
+
const handler = byMethod[req.method] ?? byMethod["GET"];
|
|
207
|
+
if (!handler)
|
|
208
|
+
return this.json({ error: "Method not allowed" }, 405);
|
|
209
|
+
let methodMap = handlerMap.get(node);
|
|
210
|
+
if (!methodMap) {
|
|
211
|
+
methodMap = Object.create(null);
|
|
212
|
+
handlerMap.set(node, methodMap);
|
|
66
213
|
}
|
|
67
|
-
if (!
|
|
68
|
-
|
|
69
|
-
return result instanceof Response ? result : this.json(result);
|
|
214
|
+
if (!methodMap[req.method]) {
|
|
215
|
+
methodMap[req.method] = this.compilePipeline(handler, (_) => params);
|
|
70
216
|
}
|
|
71
|
-
|
|
72
|
-
const next = async () => {
|
|
73
|
-
if (idx < mwLen)
|
|
74
|
-
return mw[idx++](req, next);
|
|
75
|
-
const result = await handler(req);
|
|
76
|
-
return result instanceof Response ? result : this.json(result);
|
|
77
|
-
};
|
|
78
|
-
return next();
|
|
217
|
+
return await methodMap[req.method](req);
|
|
79
218
|
} catch (err) {
|
|
219
|
+
if (this.errorHandler) {
|
|
220
|
+
try {
|
|
221
|
+
return this.errorHandler(err, req);
|
|
222
|
+
} catch {}
|
|
223
|
+
}
|
|
80
224
|
return this.json({ error: String(err) }, 500);
|
|
81
225
|
}
|
|
82
226
|
}
|
|
83
227
|
});
|
|
228
|
+
console.log(`PrinceJS v2 running at http://localhost:${port}`);
|
|
84
229
|
}
|
|
85
230
|
}
|
|
86
|
-
var prince = () => new Prince;
|
|
231
|
+
var prince = (dev = false) => new Prince(dev);
|
|
87
232
|
export {
|
|
88
233
|
prince,
|
|
89
234
|
Prince
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "princejs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.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",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"easy",
|
|
16
16
|
"princejs"
|
|
17
17
|
],
|
|
18
|
-
"author": "Matthew
|
|
18
|
+
"author": "Matthew Michael (MatthewTheCoder1218)",
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"repository": "https://github.com/MatthewTheCoder1218/princejs",
|
|
21
21
|
"publishConfig": {
|