@coderbuzz/ken 0.1.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/README.md +41 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +41 -0
- package/dist/bun-GUK26ACN.js +281 -0
- package/dist/bun-GUK26ACN.js.map +1 -0
- package/dist/chunk-2BOPD5H7.js +34 -0
- package/dist/chunk-2BOPD5H7.js.map +1 -0
- package/dist/chunk-2MK26YDD.js +269 -0
- package/dist/chunk-2MK26YDD.js.map +1 -0
- package/dist/chunk-DPU3PBLP.js +815 -0
- package/dist/chunk-DPU3PBLP.js.map +1 -0
- package/dist/chunk-WTV4URUZ.js +122 -0
- package/dist/chunk-WTV4URUZ.js.map +1 -0
- package/dist/deno-LZU5JBGL.js +250 -0
- package/dist/deno-LZU5JBGL.js.map +1 -0
- package/dist/index.d.ts +2783 -0
- package/dist/index.js +2728 -0
- package/dist/index.js.map +1 -0
- package/dist/node-JLUTIPEN.js +816 -0
- package/dist/node-JLUTIPEN.js.map +1 -0
- package/dist/package.json +13 -0
- package/dist/uws-VNY2LPIZ.js +622 -0
- package/dist/uws-VNY2LPIZ.js.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @coderbuzz/ken
|
|
2
|
+
|
|
3
|
+
# Ken
|
|
4
|
+
|
|
5
|
+
### The Modern Standard for TypeScript Backends.
|
|
6
|
+
|
|
7
|
+
Ken is a modern TypeScript backend framework designed to run seamlessly across
|
|
8
|
+
Node.js, Deno, and Bun. It focuses on clarity, speed, and a clean developer
|
|
9
|
+
experience without unnecessary abstraction.
|
|
10
|
+
|
|
11
|
+
Ken is a minimalist, high-performance, and type-safe backend framework built
|
|
12
|
+
entirely with TypeScript. Designed for the modern JavaScript ecosystem, Ken
|
|
13
|
+
ensures your application runs consistently across Node.js, Deno, and Bun. Write
|
|
14
|
+
once, deploy everywhere, and unleash the true potential of your server-side
|
|
15
|
+
code.
|
|
16
|
+
|
|
17
|
+
Ken is your next-generation TypeScript backend framework. It was engineered from
|
|
18
|
+
the ground up to deliver unparalleled developer experience (DX) and superior
|
|
19
|
+
performance. By leveraging the power of modern TypeScript and a fluent, modular
|
|
20
|
+
architecture, Ken allows developers to build scalable APIs and services with
|
|
21
|
+
absolute type safety.
|
|
22
|
+
|
|
23
|
+
### Key Features:
|
|
24
|
+
|
|
25
|
+
- Runtime Agnostic: Seamlessly run your application on Node.js, Deno, and Bun
|
|
26
|
+
without code changes.
|
|
27
|
+
|
|
28
|
+
- TypeScript Native: Full type-checking and autocompletion support out of the
|
|
29
|
+
box.
|
|
30
|
+
|
|
31
|
+
- Performance-Driven: Minimal overhead designed for maximal throughput and low
|
|
32
|
+
latency.
|
|
33
|
+
|
|
34
|
+
- Modular & Extensible: Easily integrate with existing libraries and scale
|
|
35
|
+
complexity as needed.
|
|
36
|
+
|
|
37
|
+
## Build
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun run build
|
|
41
|
+
```
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Indra Gunawan
|
|
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/dist/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @coderbuzz/ken
|
|
2
|
+
|
|
3
|
+
# Ken
|
|
4
|
+
|
|
5
|
+
### The Modern Standard for TypeScript Backends.
|
|
6
|
+
|
|
7
|
+
Ken is a modern TypeScript backend framework designed to run seamlessly across
|
|
8
|
+
Node.js, Deno, and Bun. It focuses on clarity, speed, and a clean developer
|
|
9
|
+
experience without unnecessary abstraction.
|
|
10
|
+
|
|
11
|
+
Ken is a minimalist, high-performance, and type-safe backend framework built
|
|
12
|
+
entirely with TypeScript. Designed for the modern JavaScript ecosystem, Ken
|
|
13
|
+
ensures your application runs consistently across Node.js, Deno, and Bun. Write
|
|
14
|
+
once, deploy everywhere, and unleash the true potential of your server-side
|
|
15
|
+
code.
|
|
16
|
+
|
|
17
|
+
Ken is your next-generation TypeScript backend framework. It was engineered from
|
|
18
|
+
the ground up to deliver unparalleled developer experience (DX) and superior
|
|
19
|
+
performance. By leveraging the power of modern TypeScript and a fluent, modular
|
|
20
|
+
architecture, Ken allows developers to build scalable APIs and services with
|
|
21
|
+
absolute type safety.
|
|
22
|
+
|
|
23
|
+
### Key Features:
|
|
24
|
+
|
|
25
|
+
- Runtime Agnostic: Seamlessly run your application on Node.js, Deno, and Bun
|
|
26
|
+
without code changes.
|
|
27
|
+
|
|
28
|
+
- TypeScript Native: Full type-checking and autocompletion support out of the
|
|
29
|
+
box.
|
|
30
|
+
|
|
31
|
+
- Performance-Driven: Minimal overhead designed for maximal throughput and low
|
|
32
|
+
latency.
|
|
33
|
+
|
|
34
|
+
- Modular & Extensible: Easily integrate with existing libraries and scale
|
|
35
|
+
complexity as needed.
|
|
36
|
+
|
|
37
|
+
## Build
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun run build
|
|
41
|
+
```
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WebContext
|
|
3
|
+
} from "./chunk-WTV4URUZ.js";
|
|
4
|
+
import {
|
|
5
|
+
canUseNativeRoute,
|
|
6
|
+
getPathname
|
|
7
|
+
} from "./chunk-2BOPD5H7.js";
|
|
8
|
+
import "./chunk-2MK26YDD.js";
|
|
9
|
+
import {
|
|
10
|
+
EMPTY_PARAMS,
|
|
11
|
+
Router,
|
|
12
|
+
WS_DEFAULTS,
|
|
13
|
+
createExecutor,
|
|
14
|
+
createNotFoundExecutor,
|
|
15
|
+
toResponse
|
|
16
|
+
} from "./chunk-DPU3PBLP.js";
|
|
17
|
+
|
|
18
|
+
// src/ws/bun.ts
|
|
19
|
+
var BunWsPeer = class {
|
|
20
|
+
ws;
|
|
21
|
+
constructor(ws) {
|
|
22
|
+
this.ws = ws;
|
|
23
|
+
}
|
|
24
|
+
get data() {
|
|
25
|
+
return this.ws.data.userData;
|
|
26
|
+
}
|
|
27
|
+
set data(value) {
|
|
28
|
+
this.ws.data.userData = value;
|
|
29
|
+
}
|
|
30
|
+
get remoteAddress() {
|
|
31
|
+
return this.ws.remoteAddress;
|
|
32
|
+
}
|
|
33
|
+
get readyState() {
|
|
34
|
+
return this.ws.readyState;
|
|
35
|
+
}
|
|
36
|
+
send(data, compress) {
|
|
37
|
+
return this.ws.send(data, compress);
|
|
38
|
+
}
|
|
39
|
+
close(code, reason) {
|
|
40
|
+
this.ws.close(code, reason);
|
|
41
|
+
}
|
|
42
|
+
subscribe(topic) {
|
|
43
|
+
this.ws.subscribe(topic);
|
|
44
|
+
}
|
|
45
|
+
unsubscribe(topic) {
|
|
46
|
+
this.ws.unsubscribe(topic);
|
|
47
|
+
}
|
|
48
|
+
publish(topic, data, compress) {
|
|
49
|
+
this.ws.publish(topic, data, compress);
|
|
50
|
+
}
|
|
51
|
+
isSubscribed(topic) {
|
|
52
|
+
return this.ws.isSubscribed(topic);
|
|
53
|
+
}
|
|
54
|
+
ping(data) {
|
|
55
|
+
this.ws.ping(data);
|
|
56
|
+
}
|
|
57
|
+
pong(data) {
|
|
58
|
+
this.ws.pong(data);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function createBunWsMultiConfig(wsRoutes) {
|
|
62
|
+
const mergedOpts = { ...WS_DEFAULTS };
|
|
63
|
+
for (const route of wsRoutes) {
|
|
64
|
+
if (route.options) {
|
|
65
|
+
if (route.options.maxPayloadLength !== void 0)
|
|
66
|
+
mergedOpts.maxPayloadLength = Math.max(mergedOpts.maxPayloadLength, route.options.maxPayloadLength);
|
|
67
|
+
if (route.options.backpressureLimit !== void 0)
|
|
68
|
+
mergedOpts.backpressureLimit = Math.max(mergedOpts.backpressureLimit, route.options.backpressureLimit);
|
|
69
|
+
if (route.options.pingInterval !== void 0)
|
|
70
|
+
mergedOpts.pingInterval = Math.min(mergedOpts.pingInterval, route.options.pingInterval);
|
|
71
|
+
if (route.options.idleTimeout !== void 0)
|
|
72
|
+
mergedOpts.idleTimeout = Math.max(mergedOpts.idleTimeout, route.options.idleTimeout);
|
|
73
|
+
if (route.options.perMessageDeflate)
|
|
74
|
+
mergedOpts.perMessageDeflate = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const pathMap = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const route of wsRoutes) {
|
|
79
|
+
pathMap.set(route.path, route);
|
|
80
|
+
}
|
|
81
|
+
const peerMap = /* @__PURE__ */ new WeakMap();
|
|
82
|
+
function getPeer(ws) {
|
|
83
|
+
let peer = peerMap.get(ws);
|
|
84
|
+
if (!peer) {
|
|
85
|
+
peer = new BunWsPeer(ws);
|
|
86
|
+
peerMap.set(ws, peer);
|
|
87
|
+
}
|
|
88
|
+
return peer;
|
|
89
|
+
}
|
|
90
|
+
const hasPing = wsRoutes.some((r) => r.handler.ping);
|
|
91
|
+
const hasPong = wsRoutes.some((r) => r.handler.pong);
|
|
92
|
+
const websocket = {
|
|
93
|
+
perMessageDeflate: mergedOpts.perMessageDeflate,
|
|
94
|
+
maxPayloadLength: mergedOpts.maxPayloadLength,
|
|
95
|
+
backpressureLimit: mergedOpts.backpressureLimit,
|
|
96
|
+
idleTimeout: mergedOpts.idleTimeout,
|
|
97
|
+
sendPings: mergedOpts.pingInterval > 0,
|
|
98
|
+
open(ws) {
|
|
99
|
+
const peer = getPeer(ws);
|
|
100
|
+
try {
|
|
101
|
+
ws.data._wsHandler.open?.(peer);
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
message(ws, message) {
|
|
106
|
+
const peer = getPeer(ws);
|
|
107
|
+
try {
|
|
108
|
+
ws.data._wsHandler.message(peer, message);
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
close(ws, code, reason) {
|
|
113
|
+
const peer = getPeer(ws);
|
|
114
|
+
peerMap.delete(ws);
|
|
115
|
+
try {
|
|
116
|
+
ws.data._wsHandler.close?.(peer, code, reason);
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
ping: hasPing ? (ws, data) => {
|
|
121
|
+
const handler = ws.data._wsHandler;
|
|
122
|
+
if (handler.ping) {
|
|
123
|
+
const peer = getPeer(ws);
|
|
124
|
+
try {
|
|
125
|
+
handler.ping(peer, data);
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} : void 0,
|
|
130
|
+
pong: hasPong ? (ws, data) => {
|
|
131
|
+
const handler = ws.data._wsHandler;
|
|
132
|
+
if (handler.pong) {
|
|
133
|
+
const peer = getPeer(ws);
|
|
134
|
+
try {
|
|
135
|
+
handler.pong(peer, data);
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} : void 0
|
|
140
|
+
};
|
|
141
|
+
async function upgrade(req, server2, path) {
|
|
142
|
+
const route = pathMap.get(path);
|
|
143
|
+
if (!route) return new Response("Not Found", { status: 404 });
|
|
144
|
+
let userData = void 0;
|
|
145
|
+
if (route.handler.upgrade) {
|
|
146
|
+
try {
|
|
147
|
+
const result = await route.handler.upgrade(req);
|
|
148
|
+
if (result instanceof Response) {
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
userData = result;
|
|
152
|
+
} catch {
|
|
153
|
+
return new Response("WebSocket upgrade failed", { status: 500 });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const success = server2.upgrade(req, {
|
|
157
|
+
data: {
|
|
158
|
+
_wsPath: path,
|
|
159
|
+
_wsHandler: route.handler,
|
|
160
|
+
userData
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
if (!success) {
|
|
164
|
+
return new Response("WebSocket upgrade failed", { status: 500 });
|
|
165
|
+
}
|
|
166
|
+
return void 0;
|
|
167
|
+
}
|
|
168
|
+
return { websocket, upgrade, pathMap };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/runtime/bun.ts
|
|
172
|
+
var webContextFactory = (req, params, getRemoteInfo, schema) => new WebContext(req, params, getRemoteInfo, schema);
|
|
173
|
+
function server({ port, hostname, router }) {
|
|
174
|
+
let server2 = void 0;
|
|
175
|
+
const bunRoutes = {};
|
|
176
|
+
const fallbackRouter = new Router();
|
|
177
|
+
for (const route of router.routes) {
|
|
178
|
+
let mergedSchema = route.schema;
|
|
179
|
+
if (typeof router.matchMiddleware === "function" && typeof router.mergeSchemas === "function") {
|
|
180
|
+
const matchedMiddleware = router.matchMiddleware(route.path);
|
|
181
|
+
mergedSchema = router.mergeSchemas(matchedMiddleware, route.schema);
|
|
182
|
+
}
|
|
183
|
+
if (canUseNativeRoute(route.path)) {
|
|
184
|
+
if (!bunRoutes[route.path]) bunRoutes[route.path] = {};
|
|
185
|
+
if (route.staticValue !== void 0) {
|
|
186
|
+
const cachedResponse = toResponse(route.staticValue);
|
|
187
|
+
bunRoutes[route.path][route.method] = cachedResponse;
|
|
188
|
+
} else if (route.handler) {
|
|
189
|
+
const nativeHandler = createExecutor(webContextFactory, route.handler, mergedSchema);
|
|
190
|
+
bunRoutes[route.path][route.method] = (request, bunServer) => {
|
|
191
|
+
const getRemoteInfo = () => {
|
|
192
|
+
const info = bunServer.requestIP(request);
|
|
193
|
+
return { address: info?.address ?? "", port: info?.port ?? 0 };
|
|
194
|
+
};
|
|
195
|
+
const result = nativeHandler(request, request.params || EMPTY_PARAMS, getRemoteInfo);
|
|
196
|
+
if (result && typeof result.then === "function") {
|
|
197
|
+
return result.then(toResponse);
|
|
198
|
+
}
|
|
199
|
+
return toResponse(result);
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
if (route.handler) {
|
|
204
|
+
const nativeHandler = createExecutor(webContextFactory, route.handler, mergedSchema);
|
|
205
|
+
fallbackRouter.registerCompiled(route.method, route.path, nativeHandler, mergedSchema);
|
|
206
|
+
} else if (route.staticValue !== void 0) {
|
|
207
|
+
const cachedResponse = toResponse(route.staticValue);
|
|
208
|
+
fallbackRouter.registerCompiled(route.method, route.path, () => cachedResponse, mergedSchema, cachedResponse);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const fallbackMatch = fallbackRouter.matcher();
|
|
213
|
+
const notFoundExecutor = createNotFoundExecutor(router, webContextFactory);
|
|
214
|
+
const NOT_FOUND_RESPONSE = new Response("Not Found", { status: 404 });
|
|
215
|
+
const wsRoutes = router.wsRoutes || [];
|
|
216
|
+
let bunWsConfig = null;
|
|
217
|
+
if (wsRoutes.length > 0) {
|
|
218
|
+
bunWsConfig = createBunWsMultiConfig(wsRoutes);
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
async run() {
|
|
222
|
+
server2?.stop();
|
|
223
|
+
return new Promise((resolve) => {
|
|
224
|
+
server2 = Bun.serve({
|
|
225
|
+
port,
|
|
226
|
+
hostname,
|
|
227
|
+
development: false,
|
|
228
|
+
routes: bunRoutes,
|
|
229
|
+
// Bun requires a single websocket config
|
|
230
|
+
websocket: bunWsConfig?.websocket,
|
|
231
|
+
// Fallback fetch handler for optional params, wildcards, and WS upgrades
|
|
232
|
+
fetch: (request, bunServer) => {
|
|
233
|
+
const pathname = getPathname(request.url);
|
|
234
|
+
if (bunWsConfig && request.headers.get("upgrade") === "websocket") {
|
|
235
|
+
return bunWsConfig.upgrade(request, bunServer, pathname).then((response) => {
|
|
236
|
+
if (response) return response;
|
|
237
|
+
return void 0;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
const matchResult = fallbackMatch(request.method, pathname);
|
|
241
|
+
if (matchResult !== void 0) {
|
|
242
|
+
if (matchResult.response !== void 0) {
|
|
243
|
+
return matchResult.response.clone();
|
|
244
|
+
}
|
|
245
|
+
const getRemoteInfo = () => {
|
|
246
|
+
const info = bunServer.requestIP(request);
|
|
247
|
+
return { address: info?.address ?? "", port: info?.port ?? 0 };
|
|
248
|
+
};
|
|
249
|
+
const result = matchResult.handler(request, matchResult.params, getRemoteInfo);
|
|
250
|
+
if (result && typeof result.then === "function") {
|
|
251
|
+
return result.then(toResponse);
|
|
252
|
+
}
|
|
253
|
+
return toResponse(result);
|
|
254
|
+
}
|
|
255
|
+
if (notFoundExecutor) {
|
|
256
|
+
const getRemoteInfo = () => {
|
|
257
|
+
const info = bunServer.requestIP(request);
|
|
258
|
+
return { address: info?.address ?? "", port: info?.port ?? 0 };
|
|
259
|
+
};
|
|
260
|
+
const result = notFoundExecutor(request, getRemoteInfo, pathname);
|
|
261
|
+
if (result && typeof result.then === "function") {
|
|
262
|
+
return result.then(toResponse);
|
|
263
|
+
}
|
|
264
|
+
return toResponse(result);
|
|
265
|
+
}
|
|
266
|
+
return NOT_FOUND_RESPONSE.clone();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
resolve({ hostname: server2.hostname, port: server2.port });
|
|
270
|
+
});
|
|
271
|
+
},
|
|
272
|
+
stop() {
|
|
273
|
+
server2?.stop();
|
|
274
|
+
server2 = void 0;
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
export {
|
|
279
|
+
server
|
|
280
|
+
};
|
|
281
|
+
//# sourceMappingURL=bun-GUK26ACN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ws/bun.ts","../src/runtime/bun.ts"],"sourcesContent":["/**\n * Ken Framework - Bun WebSocket Adapter\n * Uses Bun's native WebSocket support for maximum performance\n * \n * Bun provides built-in WebSocket with pub/sub, compression,\n * and automatic ping/pong — we leverage all of it.\n * \n * NOTE: Bun only supports a single `websocket` config per server.\n * Multiple .ws() paths are dispatched via a routing layer stored in ws.data.\n * \n * MIT License - Copyright (c) 2025 Indra Gunawan\n */\n\nimport {\n type WsPeer,\n type WsHandler,\n type WsOptions,\n type WsMessageData,\n type WsReadyStateValue,\n type WsRoute,\n WS_DEFAULTS,\n} from './types';\nimport { type PubSubPeer } from './pubsub';\n\n// ==================== Bun WebSocket Types ====================\n\ninterface BunServerWebSocket<T> {\n readonly data: T;\n readonly readyState: number;\n readonly remoteAddress: string;\n send(data: string | ArrayBuffer | Uint8Array, compress?: boolean): number;\n close(code?: number, reason?: string): void;\n subscribe(topic: string): void;\n unsubscribe(topic: string): void;\n publish(topic: string, data: string | ArrayBuffer | Uint8Array, compress?: boolean): void;\n isSubscribed(topic: string): boolean;\n ping(data?: string | ArrayBuffer | Uint8Array): void;\n pong(data?: string | ArrayBuffer | Uint8Array): void;\n}\n\n/**\n * Internal data stored on each Bun WebSocket connection.\n * Contains the path-specific handler and user data.\n */\ninterface BunWsData {\n /** The path this connection was upgraded on */\n _wsPath: string;\n /** The handler for this path */\n _wsHandler: WsHandler<any>;\n /** User-provided per-connection data */\n userData: any;\n}\n\n// ==================== BunWsPeer ====================\n\n/**\n * Bun WebSocket peer — thin wrapper over Bun's native ServerWebSocket.\n * Delegates pub/sub directly to Bun's native implementation.\n */\nclass BunWsPeer<T> implements WsPeer<T>, PubSubPeer {\n private ws: BunServerWebSocket<BunWsData>;\n\n constructor(ws: BunServerWebSocket<BunWsData>) {\n this.ws = ws;\n }\n\n get data(): T {\n return this.ws.data.userData;\n }\n\n set data(value: T) {\n this.ws.data.userData = value;\n }\n\n get remoteAddress(): string {\n return this.ws.remoteAddress;\n }\n\n get readyState(): WsReadyStateValue {\n return this.ws.readyState as WsReadyStateValue;\n }\n\n send(data: WsMessageData, compress?: boolean): number {\n return this.ws.send(data as any, compress);\n }\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n\n subscribe(topic: string): void {\n this.ws.subscribe(topic);\n }\n\n unsubscribe(topic: string): void {\n this.ws.unsubscribe(topic);\n }\n\n publish(topic: string, data: WsMessageData, compress?: boolean): void {\n this.ws.publish(topic, data as any, compress);\n }\n\n isSubscribed(topic: string): boolean {\n return this.ws.isSubscribed(topic);\n }\n\n ping(data?: WsMessageData): void {\n this.ws.ping(data as any);\n }\n\n pong(data?: WsMessageData): void {\n this.ws.pong(data as any);\n }\n}\n\n// ==================== Bun Multi-Path WebSocket Config ====================\n\n/**\n * Build a single Bun-native websocket config that dispatches to\n * multiple path-specific handlers.\n * \n * Used by the Bun runtime adapter to configure `Bun.serve({ websocket })`.\n */\nexport function createBunWsMultiConfig(\n wsRoutes: WsRoute<any>[],\n): {\n websocket: {\n open(ws: BunServerWebSocket<BunWsData>): void;\n message(ws: BunServerWebSocket<BunWsData>, message: string | Buffer): void;\n close(ws: BunServerWebSocket<BunWsData>, code: number, reason: string): void;\n ping?(ws: BunServerWebSocket<BunWsData>, data: Buffer): void;\n pong?(ws: BunServerWebSocket<BunWsData>, data: Buffer): void;\n perMessageDeflate?: boolean;\n maxPayloadLength?: number;\n backpressureLimit?: number;\n idleTimeout?: number;\n sendPings?: boolean;\n };\n upgrade: (req: Request, server: any, path: string) => Promise<Response | undefined>;\n pathMap: Map<string, WsRoute<any>>;\n} {\n // Merge options from all routes (use largest / most permissive values)\n const mergedOpts: Required<WsOptions> = { ...WS_DEFAULTS };\n for (const route of wsRoutes) {\n if (route.options) {\n if (route.options.maxPayloadLength !== undefined)\n mergedOpts.maxPayloadLength = Math.max(mergedOpts.maxPayloadLength, route.options.maxPayloadLength);\n if (route.options.backpressureLimit !== undefined)\n mergedOpts.backpressureLimit = Math.max(mergedOpts.backpressureLimit, route.options.backpressureLimit);\n if (route.options.pingInterval !== undefined)\n mergedOpts.pingInterval = Math.min(mergedOpts.pingInterval, route.options.pingInterval);\n if (route.options.idleTimeout !== undefined)\n mergedOpts.idleTimeout = Math.max(mergedOpts.idleTimeout, route.options.idleTimeout);\n if (route.options.perMessageDeflate)\n mergedOpts.perMessageDeflate = true;\n }\n }\n\n // Build path -> route map\n const pathMap = new Map<string, WsRoute<any>>();\n for (const route of wsRoutes) {\n pathMap.set(route.path, route);\n }\n\n // Peer lookup: native ws -> KenPeer\n const peerMap = new WeakMap<BunServerWebSocket<BunWsData>, BunWsPeer<any>>();\n\n function getPeer(ws: BunServerWebSocket<BunWsData>): BunWsPeer<any> {\n let peer = peerMap.get(ws);\n if (!peer) {\n peer = new BunWsPeer(ws);\n peerMap.set(ws, peer);\n }\n return peer;\n }\n\n // Check if any route has ping/pong handlers\n const hasPing = wsRoutes.some(r => r.handler.ping);\n const hasPong = wsRoutes.some(r => r.handler.pong);\n\n const websocket = {\n perMessageDeflate: mergedOpts.perMessageDeflate,\n maxPayloadLength: mergedOpts.maxPayloadLength,\n backpressureLimit: mergedOpts.backpressureLimit,\n idleTimeout: mergedOpts.idleTimeout,\n sendPings: mergedOpts.pingInterval > 0,\n\n open(ws: BunServerWebSocket<BunWsData>): void {\n const peer = getPeer(ws);\n try {\n ws.data._wsHandler.open?.(peer);\n } catch { /* ignore */ }\n },\n\n message(ws: BunServerWebSocket<BunWsData>, message: string | Buffer): void {\n const peer = getPeer(ws);\n try {\n ws.data._wsHandler.message(peer, message);\n } catch { /* ignore */ }\n },\n\n close(ws: BunServerWebSocket<BunWsData>, code: number, reason: string): void {\n const peer = getPeer(ws);\n peerMap.delete(ws);\n try {\n ws.data._wsHandler.close?.(peer, code, reason);\n } catch { /* ignore */ }\n },\n\n ping: hasPing ? (ws: BunServerWebSocket<BunWsData>, data: Buffer): void => {\n const handler = ws.data._wsHandler;\n if (handler.ping) {\n const peer = getPeer(ws);\n try {\n handler.ping(peer, data);\n } catch { /* ignore */ }\n }\n } : undefined,\n\n pong: hasPong ? (ws: BunServerWebSocket<BunWsData>, data: Buffer): void => {\n const handler = ws.data._wsHandler;\n if (handler.pong) {\n const peer = getPeer(ws);\n try {\n handler.pong(peer, data);\n } catch { /* ignore */ }\n }\n } : undefined,\n };\n\n async function upgrade(req: Request, server: any, path: string): Promise<Response | undefined> {\n const route = pathMap.get(path);\n if (!route) return new Response('Not Found', { status: 404 });\n\n let userData: any = undefined;\n\n if (route.handler.upgrade) {\n try {\n const result = await route.handler.upgrade(req);\n if (result instanceof Response) {\n return result; // Reject upgrade\n }\n userData = result;\n } catch {\n return new Response('WebSocket upgrade failed', { status: 500 });\n }\n }\n\n const success = server.upgrade(req, {\n data: {\n _wsPath: path,\n _wsHandler: route.handler,\n userData,\n },\n });\n\n if (!success) {\n return new Response('WebSocket upgrade failed', { status: 500 });\n }\n\n return undefined; // Success — no response needed\n }\n\n return { websocket, upgrade, pathMap };\n}\n","/**\n * Ken Framework - Bun Runtime\n * High-performance runtime using Bun's native routes optimization\n * \n * OPTIMIZATION STRATEGY:\n * ---------------------\n * Bun's native routes (serve({ routes })) are extremely fast.\n * Support: static routes and regular params (:id)\n * NOT supported: optional params (:id?) or wildcards (*)\n * \n * This runtime uses a two-tier approach:\n * 1. Static routes + regular params → Bun native routes (fastest)\n * 2. Optional params + wildcards → JS Router fallback\n * \n * MIT License - Copyright (c) 2025 Indra Gunawan\n */\n\nimport { Router } from '../core/router';\nimport { WebContext } from '../context/web';\nimport { type Schema, type GetRemoteInfo, EMPTY_PARAMS } from '../context/types';\nimport { createExecutor, createNotFoundExecutor, type ContextFactory } from './compiler';\nimport { toResponse } from '../utils/response';\nimport { getPathname, canUseNativeRoute } from '../utils/pathname';\nimport { type WsRoute } from '../ws/types';\nimport { createBunWsMultiConfig } from '../ws/bun';\n\n/**\n * Bun-specific Request type with params\n */\ninterface BunRequest<T extends string = string> extends Request {\n params: Record<T, string>;\n}\n\n/**\n * Bun route handler type\n */\ntype BunRouteHandler = Response | ((request: BunRequest, server: BunServer) => Response | Promise<Response>);\n\n/**\n * Bun server interface\n */\ninterface BunServer {\n requestIP: (req: Request) => { address: string; port: number; } | null;\n}\n\ndeclare const Bun: {\n serve(options: {\n port?: number;\n hostname?: string;\n development?: boolean;\n routes?: Record<string, BunRouteHandler | Record<string, BunRouteHandler>>;\n fetch?: (request: Request, server: BunServer) => Response | Promise<Response>;\n websocket?: any;\n }): { hostname: string; port: number; stop: () => void; upgrade: (req: Request, options?: any) => boolean; };\n};\n\n/**\n * WebContext factory for Bun runtime\n */\nconst webContextFactory: ContextFactory<Request, WebContext> = (\n req: Request,\n params: Record<string, string>,\n getRemoteInfo: GetRemoteInfo,\n schema?: Schema\n) => new WebContext(req, params, getRemoteInfo, schema);\n\nexport function server({ port, hostname, router }: {\n port?: number;\n hostname?: string;\n router: Router;\n}) {\n let server: { hostname: string; port: number; stop: () => void; } | undefined = undefined;\n\n // Build Bun native routes and fallback Router\n const bunRoutes: Record<string, Record<string, BunRouteHandler>> = {};\n const fallbackRouter = new Router();\n\n // Compile routes\n for (const route of router.routes) {\n // Get merged schema (App provides middleware merging)\n let mergedSchema = route.schema;\n if (typeof (router as any).matchMiddleware === 'function' && typeof (router as any).mergeSchemas === 'function') {\n const matchedMiddleware = (router as any).matchMiddleware(route.path);\n mergedSchema = (router as any).mergeSchemas(matchedMiddleware, route.schema);\n }\n\n // Check if route can use native routing\n if (canUseNativeRoute(route.path)) {\n // Initialize path object\n if (!bunRoutes[route.path]) bunRoutes[route.path] = {};\n\n // Static value optimization: Direct Response (no function wrapper)\n if (route.staticValue !== undefined) {\n const cachedResponse = toResponse(route.staticValue);\n bunRoutes[route.path][route.method] = cachedResponse;\n } else if (route.handler) {\n // Create executor for this route\n const nativeHandler = createExecutor(webContextFactory, route.handler, mergedSchema);\n\n // Wrap for Bun native routes\n bunRoutes[route.path][route.method] = (request: BunRequest, bunServer: BunServer) => {\n const getRemoteInfo: GetRemoteInfo = () => {\n const info = bunServer.requestIP(request);\n return { address: info?.address ?? '', port: info?.port ?? 0 };\n };\n const result = nativeHandler(request, request.params || EMPTY_PARAMS, getRemoteInfo);\n\n // Handle async results\n if (result && typeof result.then === 'function') {\n return result.then(toResponse);\n }\n return toResponse(result);\n };\n }\n } else {\n // Optional params or wildcards → fallback Router\n if (route.handler) {\n const nativeHandler = createExecutor(webContextFactory, route.handler, mergedSchema);\n fallbackRouter.registerCompiled(route.method, route.path, nativeHandler, mergedSchema);\n } else if (route.staticValue !== undefined) {\n const cachedResponse = toResponse(route.staticValue);\n fallbackRouter.registerCompiled(route.method, route.path, () => cachedResponse, mergedSchema, cachedResponse);\n }\n }\n }\n\n // Get matcher for fallback router\n const fallbackMatch = fallbackRouter.matcher();\n\n // Pre-compile 404 handler with global middleware\n const notFoundExecutor = createNotFoundExecutor(router, webContextFactory);\n const NOT_FOUND_RESPONSE = new Response('Not Found', { status: 404 });\n\n // WebSocket routes\n const wsRoutes: WsRoute<any>[] = (router as any).wsRoutes || [];\n let bunWsConfig: ReturnType<typeof createBunWsMultiConfig> | null = null;\n\n if (wsRoutes.length > 0) {\n bunWsConfig = createBunWsMultiConfig(wsRoutes);\n }\n\n return {\n async run(): Promise<{ hostname: string; port: number; }> {\n server?.stop();\n return new Promise((resolve) => {\n server = Bun.serve({\n port,\n hostname,\n development: false,\n routes: bunRoutes,\n\n // Bun requires a single websocket config\n websocket: bunWsConfig?.websocket,\n\n // Fallback fetch handler for optional params, wildcards, and WS upgrades\n fetch: (request, bunServer) => {\n const pathname = getPathname(request.url);\n\n // Check for WebSocket upgrade\n if (bunWsConfig && request.headers.get('upgrade') === 'websocket') {\n return bunWsConfig.upgrade(request, bunServer, pathname).then(response => {\n if (response) return response; // Error or rejection\n return undefined as any; // Upgrade succeeded\n });\n }\n const matchResult = fallbackMatch(request.method, pathname);\n\n if (matchResult !== undefined) {\n // Fast path: static route (skip getRemoteInfo and toResponse)\n if (matchResult.response !== undefined) {\n return matchResult.response.clone();\n }\n\n const getRemoteInfo: GetRemoteInfo = () => {\n const info = bunServer.requestIP(request);\n return { address: info?.address ?? '', port: info?.port ?? 0 };\n };\n\n const result = matchResult.handler(request, matchResult.params, getRemoteInfo);\n\n // Handle async results\n if (result && typeof result.then === 'function') {\n return result.then(toResponse);\n }\n return toResponse(result);\n }\n\n // Execute 404 with middleware if available\n if (notFoundExecutor) {\n const getRemoteInfo: GetRemoteInfo = () => {\n const info = bunServer.requestIP(request);\n return { address: info?.address ?? '', port: info?.port ?? 0 };\n };\n const result = notFoundExecutor(request, getRemoteInfo, pathname);\n if (result && typeof result.then === 'function') {\n return result.then(toResponse);\n }\n return toResponse(result);\n }\n\n return NOT_FOUND_RESPONSE.clone();\n }\n });\n\n resolve({ hostname: server.hostname, port: server.port });\n });\n },\n stop() {\n server?.stop();\n server = undefined;\n }\n };\n}\n\n// console.log('Bun runtime module loaded.');"],"mappings":"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","names":["server","server"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/utils/pathname.ts
|
|
2
|
+
function getPathname(url) {
|
|
3
|
+
const firstChar = url.charCodeAt(0);
|
|
4
|
+
if (firstChar === 47) {
|
|
5
|
+
const queryIndex2 = url.indexOf("?");
|
|
6
|
+
return queryIndex2 === -1 ? url : url.substring(0, queryIndex2);
|
|
7
|
+
}
|
|
8
|
+
const protocolEnd = url.indexOf("://");
|
|
9
|
+
if (protocolEnd === -1) {
|
|
10
|
+
const queryIndex2 = url.indexOf("?");
|
|
11
|
+
return queryIndex2 === -1 ? url : url.substring(0, queryIndex2);
|
|
12
|
+
}
|
|
13
|
+
const pathStart = url.indexOf("/", protocolEnd + 3);
|
|
14
|
+
if (pathStart === -1) {
|
|
15
|
+
return "/";
|
|
16
|
+
}
|
|
17
|
+
const queryIndex = url.indexOf("?", pathStart);
|
|
18
|
+
return queryIndex === -1 ? url.substring(pathStart) : url.substring(pathStart, queryIndex);
|
|
19
|
+
}
|
|
20
|
+
function hasOptionalParams(path) {
|
|
21
|
+
return path.includes("?");
|
|
22
|
+
}
|
|
23
|
+
function hasWildcard(path) {
|
|
24
|
+
return path.includes("*");
|
|
25
|
+
}
|
|
26
|
+
function canUseNativeRoute(path) {
|
|
27
|
+
return !hasOptionalParams(path) && !hasWildcard(path);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
getPathname,
|
|
32
|
+
canUseNativeRoute
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=chunk-2BOPD5H7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/pathname.ts"],"sourcesContent":["/**\n * Ken Framework - Pathname Utilities\n * Fast pathname extraction from URLs\n * \n * MIT License - Copyright (c) 2025 Indra Gunawan\n */\n\n/**\n * Fast pathname extraction from URL string\n * Optimized for hot path - avoids URL object creation\n */\nexport function getPathname(url: string): string {\n const firstChar = url.charCodeAt(0);\n\n // Fast path: relative URL starting with '/' (most common in routing)\n if (firstChar === 47) { // '/'\n const queryIndex = url.indexOf('?');\n return queryIndex === -1 ? url : url.substring(0, queryIndex);\n }\n\n // Full URL: find protocol and extract path\n const protocolEnd = url.indexOf('://');\n if (protocolEnd === -1) {\n // No protocol - treat as path\n const queryIndex = url.indexOf('?');\n return queryIndex === -1 ? url : url.substring(0, queryIndex);\n }\n\n // Find path start after host\n const pathStart = url.indexOf('/', protocolEnd + 3);\n if (pathStart === -1) {\n return '/';\n }\n\n const queryIndex = url.indexOf('?', pathStart);\n return queryIndex === -1 ? url.substring(pathStart) : url.substring(pathStart, queryIndex);\n}\n\n/**\n * Check if route path contains optional params\n */\nexport function hasOptionalParams(path: string): boolean {\n return path.includes('?');\n}\n\n/**\n * Check if route path contains wildcard\n */\nexport function hasWildcard(path: string): boolean {\n return path.includes('*');\n}\n\n/**\n * Check if route path contains any dynamic segments (params)\n */\nexport function hasParams(path: string): boolean {\n return path.includes(':');\n}\n\n/**\n * Check if route can use native routing (Bun/uWS)\n * Returns true for static and regular params, false for optional/wildcard\n */\nexport function canUseNativeRoute(path: string): boolean {\n return !hasOptionalParams(path) && !hasWildcard(path);\n}\n\n/**\n * Extract param names from route path\n * Used for uWS param extraction by index\n */\nexport function extractParamNames(path: string): string[] {\n const names: string[] = [];\n const parts = path.split('/');\n\n for (const part of parts) {\n if (part.startsWith(':')) {\n // Remove trailing ? for optional params\n const name = part.endsWith('?') ? part.slice(1, -1) : part.slice(1);\n names.push(name);\n }\n }\n\n return names;\n}\n"],"mappings":";AAWO,SAAS,YAAY,KAAqB;AAC/C,QAAM,YAAY,IAAI,WAAW,CAAC;AAGlC,MAAI,cAAc,IAAI;AACpB,UAAMA,cAAa,IAAI,QAAQ,GAAG;AAClC,WAAOA,gBAAe,KAAK,MAAM,IAAI,UAAU,GAAGA,WAAU;AAAA,EAC9D;AAGA,QAAM,cAAc,IAAI,QAAQ,KAAK;AACrC,MAAI,gBAAgB,IAAI;AAEtB,UAAMA,cAAa,IAAI,QAAQ,GAAG;AAClC,WAAOA,gBAAe,KAAK,MAAM,IAAI,UAAU,GAAGA,WAAU;AAAA,EAC9D;AAGA,QAAM,YAAY,IAAI,QAAQ,KAAK,cAAc,CAAC;AAClD,MAAI,cAAc,IAAI;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,IAAI,QAAQ,KAAK,SAAS;AAC7C,SAAO,eAAe,KAAK,IAAI,UAAU,SAAS,IAAI,IAAI,UAAU,WAAW,UAAU;AAC3F;AAKO,SAAS,kBAAkB,MAAuB;AACvD,SAAO,KAAK,SAAS,GAAG;AAC1B;AAKO,SAAS,YAAY,MAAuB;AACjD,SAAO,KAAK,SAAS,GAAG;AAC1B;AAaO,SAAS,kBAAkB,MAAuB;AACvD,SAAO,CAAC,kBAAkB,IAAI,KAAK,CAAC,YAAY,IAAI;AACtD;","names":["queryIndex"]}
|